[squeak-dev] The Inbox: Metacello-MC-ct.740.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Jul 14 14:14:30 UTC 2022


A new version of Metacello-MC was added to project The Inbox:
http://source.squeak.org/inbox/Metacello-MC-ct.740.mcz

==================== Summary ====================

Name: Metacello-MC-ct.740
Author: ct
Time: 7 November 2020, 3:04:55.670274 pm
UUID: 29d84de4-0aaf-304b-99e4-b08db78c9072
Ancestors: Metacello-MC-tobe.739

Complements Metacello-Core-ct.834. In particular, this patch introduces MetacelloRepositorySpec >> #updateRepository: to overcome invalidations when fetching an existing repository with different credentials again.

==================== Snapshot ====================

SystemOrganization addCategory: #'Metacello-MC'!
SystemOrganization addCategory: #'Metacello-MC-Directives'!
SystemOrganization addCategory: #'Metacello-MC-Gofer'!
SystemOrganization addCategory: #'Metacello-MC-Loaders'!
SystemOrganization addCategory: #'Metacello-MC-Model'!
SystemOrganization addCategory: #'Metacello-MC-Specs'!
SystemOrganization addCategory: #'Metacello-MC-Validation'!

MetacelloSpecLoader subclass: #MetacelloCommonMCSpecLoader
	instanceVariableNames: 'operator loaderPolicy disablePackageCache'
	classVariableNames: 'RetryPackageResolution'
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloCommonMCSpecLoader class>>nameComponentsFrom: (in category 'utilities') -----
nameComponentsFrom: aVersionName
	| ar |
	ar := (aVersionName last isDigit and: [ (aVersionName indexOf: $.) > 0 ])ifFalse: [Array with: aVersionName with: '' with: 0 with: aVersionName with: self]
		ifTrue: [ | vrsn str |
			str := ((aVersionName copyAfterLast: $-) copyAfterLast: $.).
			vrsn := str isEmpty
				ifTrue: [0]
				ifFalse: [str asInteger].
			Array
				with: (aVersionName copyUpToLast:  $-)								"base pkg name"
				with: ((aVersionName copyAfterLast: $-) copyUpTo: $.)				"user"
				with:  vrsn "version"
				with: aVersionName
				with: self ].
	^ar!

----- Method: MetacelloCommonMCSpecLoader class>>retryPackageResolution (in category 'accessing') -----
retryPackageResolution
    "if true, 
		errors during #retryingResolvePackageSpecReferences:gofer: are caught and 
		the resolution is retried 3 times. After the thrid time, a MetacelloPackageSpecResolutionError
		is thrown
	if false,
		an error during #retryingResolvePackageSpecReferences:gofer: will be passed,
		likely resulting in a walkback ... useful for debugging."

    RetryPackageResolution ifNil: [ RetryPackageResolution := true ].
    ^ RetryPackageResolution!

----- Method: MetacelloCommonMCSpecLoader class>>retryPackageResolution: (in category 'accessing') -----
retryPackageResolution: aBool
    RetryPackageResolution := aBool!

----- Method: MetacelloCommonMCSpecLoader>>ancestorsFor: (in category 'versionInfo') -----
ancestorsFor: packageSpec

	| cacheKey vi |
	cacheKey := packageSpec file.
	^MetacelloPlatform current
		stackCacheFor: #ancestors
		at: cacheKey
		doing: [ :cache | 
			vi := packageSpec ancestors.
			cache at: cacheKey put: vi ].!

----- Method: MetacelloCommonMCSpecLoader>>currentVersionInfoFor: (in category 'versionInfo') -----
currentVersionInfoFor: packageSpec

	| cacheKey vi |
	cacheKey := packageSpec file.
	^MetacelloPlatform current
		stackCacheFor: #currentVersionInfo
		at: cacheKey
		doing: [ :cache | 
			vi := packageSpec currentVersionInfo.
			cache at: cacheKey put: vi ].!

----- Method: MetacelloCommonMCSpecLoader>>doLoad (in category 'actions') -----
doLoad

	self subclassResponsibility!

----- Method: MetacelloCommonMCSpecLoader>>doingLoads: (in category 'actions') -----
doingLoads: aBlock
	"escape mechanism for recording and null loaders to skip doing loaderlike things"
	
	aBlock value!

----- Method: MetacelloCommonMCSpecLoader>>ensureForDevelopment (in category 'testing') -----
ensureForDevelopment
  ^ true!

----- Method: MetacelloCommonMCSpecLoader>>ensureSpecLoader (in category 'accessing') -----
ensureSpecLoader
	^ self!

----- Method: MetacelloCommonMCSpecLoader>>fetchingSpecLoader (in category 'accessing') -----
fetchingSpecLoader

	^self!

----- Method: MetacelloCommonMCSpecLoader>>hasRepositoryOverrides (in category 'testing') -----
hasRepositoryOverrides

	^self loaderPolicy hasRepositoryOverrides!

----- Method: MetacelloCommonMCSpecLoader>>ignoreImage (in category 'accessing') -----
ignoreImage

	^self loaderPolicy ignoreImage!

----- Method: MetacelloCommonMCSpecLoader>>initialize (in category 'initialize-release') -----
initialize

	self loaderPolicy!

----- Method: MetacelloCommonMCSpecLoader>>linearLoadPackageSpec:gofer: (in category 'actions') -----
linearLoadPackageSpec: packageSpec gofer: gofer

	self subclassResponsibility!

----- Method: MetacelloCommonMCSpecLoader>>linearLoadPackageSpecs:repositories: (in category 'private') -----
linearLoadPackageSpecs: packageSpecs repositories: repositories
	
	| gofer |
	gofer := MetacelloGofer new.
	repositories do: [:repo | gofer repository: repo ].
	packageSpecs do: [:pkg | pkg loadUsing: self gofer: gofer ].!

----- Method: MetacelloCommonMCSpecLoader>>load (in category 'actions') -----
load
	| repos |
	repos := self repositoriesFrom: self spec repositorySpecs.
	^ self loadType == #atomic
		ifTrue: [self atomicLoadPackageSpecs: self spec packageSpecsInLoadOrder repositories: repos]
		ifFalse: ["assume #linear"
			self linearLoadPackageSpecs: self spec packageSpecsInLoadOrder repositories: repos ]!

----- Method: MetacelloCommonMCSpecLoader>>loadPackageDirective:gofer: (in category 'actions') -----
loadPackageDirective: aPackageLoadDirective gofer: aGofer
  | packageSpec |
  packageSpec := aPackageLoadDirective spec.
  MetacelloPlatform current
    do: [ 
      | loadBlock goferLoad answers resolvedReference |
      aGofer disablePackageCache.	"for good luck:)"
      resolvedReference := self resolvePackageSpec: packageSpec gofer: aGofer.
      resolvedReference isNil
        ifTrue: [ 
          "Package version already loaded into image"
          ^ self ].
      loadBlock := [ 
      "mcLoader preLoad: packageSpec."
      goferLoad := MetacelloGoferLoad on: aGofer.
      goferLoad addResolved: resolvedReference.
      goferLoad execute.
      MetacelloPlatform current clearCurrentVersionCache	"mcLoader postLoad: packageSpec" ].
      (answers := packageSpec answers) notEmpty
        ifTrue: [ loadBlock valueSupplyingMetacelloAnswers: answers ]
        ifFalse: [ loadBlock value ].
      resolvedReference workingCopy repositoryGroup
        addRepository: aPackageLoadDirective repository.
      Transcript
        cr;
        show:
            'Loaded -> ' , resolvedReference name , ' --- '
                , aPackageLoadDirective repository repositoryDescription
                , ' --- ' , resolvedReference repository description ]
    displaying: 'Loading ' , packageSpec file!

----- Method: MetacelloCommonMCSpecLoader>>loadPackageDirectives:gofer: (in category 'actions') -----
loadPackageDirectives: pkgLoads gofer: aGofer
  MetacelloPlatform current
    do: [ 
      | goferLoad loadBlock answers |
      goferLoad := MetacelloGoferLoad on: aGofer.
      answers := OrderedCollection new.
      pkgLoads
        do: [ :packageLoadDirective | 
          | resolvedReference |
          aGofer disablePackageCache.	"for good luck:)"
          (resolvedReference := self
            resolvePackageSpec: packageLoadDirective spec
            gofer: aGofer) ~~ nil
            ifTrue: [ 
              goferLoad addResolved: resolvedReference.
              answers addAll: packageLoadDirective spec answers.
              packageLoadDirective resolvedReference: resolvedReference ] ].
      Transcript
        cr;
        show: 'Starting atomic load'.
      loadBlock := [ 
      "pkgLoads do: [:packageLoadDirective |  mcLoader preLoad: packageLoadDirective spec ]."
      goferLoad execute.
      pkgLoads
        do: [ :packageLoadDirective | 
          packageLoadDirective resolvedReference == nil
            ifTrue: [ 
              Transcript
                cr;
                tab;
                show: 'Already Loaded -> ' , packageLoadDirective file ]
            ifFalse: [ 
              Transcript
                cr;
                tab;
                show:
                    'Loaded -> ' , packageLoadDirective file , ' --- '
                        , packageLoadDirective repository repositoryDescription
                        , ' --- '
                        ,
                          packageLoadDirective resolvedReference repository description.
              packageLoadDirective resolvedReference workingCopy repositoryGroup
                addRepository: packageLoadDirective repository ] ].
      MetacelloPlatform current clearCurrentVersionCache	"pkgLoads do: [:packageLoadDirective | 
					packageLoadDirective resolvedReference ~~ nil
						ifTrue: [mcLoader postLoad: packageLoadDirective spec ]]" ].
      answers notEmpty
        ifTrue: [ loadBlock valueSupplyingMetacelloAnswers: answers ]
        ifFalse: [ loadBlock value ].
      Transcript
        cr;
        show: 'Finished atomic load' ]
    displaying: 'Atomic Load...'!

----- Method: MetacelloCommonMCSpecLoader>>loaderPolicy (in category 'accessing') -----
loaderPolicy

	loaderPolicy == nil ifTrue: [ loaderPolicy := MetacelloLoaderPolicy new ].
	^loaderPolicy!

----- Method: MetacelloCommonMCSpecLoader>>loaderPolicy: (in category 'accessing') -----
loaderPolicy: anObject
	loaderPolicy := anObject!

----- Method: MetacelloCommonMCSpecLoader>>loadingSpecLoader (in category 'accessing') -----
loadingSpecLoader

	^self!

----- Method: MetacelloCommonMCSpecLoader>>nameComponentsFrom: (in category 'packages') -----
nameComponentsFrom: aVersionName

	^self class nameComponentsFrom: aVersionName!

----- Method: MetacelloCommonMCSpecLoader>>operator (in category 'accessing') -----
operator

	operator == nil ifTrue: [ ^#= ].
	^operator!

----- Method: MetacelloCommonMCSpecLoader>>operator: (in category 'accessing') -----
operator: aSymbol

	operator := aSymbol!

----- Method: MetacelloCommonMCSpecLoader>>postLoad: (in category 'doits') -----
postLoad: packageOrVersionSpec
	"subclassResponsibility, but it gets called during an upgrade, so leave it as NOOP"!

----- Method: MetacelloCommonMCSpecLoader>>preLoad: (in category 'doits') -----
preLoad: packageOrVersionSpec

	self subclassResponsibility!

----- Method: MetacelloCommonMCSpecLoader>>recordingSpecLoader (in category 'accessing') -----
recordingSpecLoader

	^(MetacelloNullRecordingMCSpecLoader on: self spec)
		shouldDisablePackageCache: self shouldDisablePackageCache;
		loaderPolicy: self loaderPolicy copy;
		yourself!

----- Method: MetacelloCommonMCSpecLoader>>repositoriesFrom: (in category 'repositories') -----
repositoriesFrom: aMetacelloMVRepositorySpecs

	^self repositoriesFrom: aMetacelloMVRepositorySpecs ignoreOverrides: false!

----- Method: MetacelloCommonMCSpecLoader>>repositoriesFrom:ignoreOverrides: (in category 'repositories') -----
repositoriesFrom: aMetacelloMVRepositorySpecs ignoreOverrides: ignoreOverrides

	| repositories repos |
	(ignoreOverrides not and: [self hasRepositoryOverrides]) ifTrue: [ ^self loaderPolicy overrideRepositories ].
	repositories := MCRepositoryGroup default repositories.
	repos := OrderedCollection new.
	aMetacelloMVRepositorySpecs do: [:aSpec | | description repo |
		description := aSpec description.
		(repo := repositories
			detect: [ :rep | rep description = description ]
			ifNone: [ aSpec createRepository ]) ~~ nil
				ifTrue: [ repos add: (aSpec updateRepository: repo) ]].
	^repos!

----- Method: MetacelloCommonMCSpecLoader>>repositoryMap (in category 'accessing') -----
repositoryMap

	^self loaderPolicy repositoryMap!

----- Method: MetacelloCommonMCSpecLoader>>resolvePackageSpec:gofer: (in category 'private') -----
resolvePackageSpec: packageSpec gofer: gofer
  | references resolvedReference mcVersion loadedVersionInfos |
  references := self
    retryingResolvePackageSpecReferences: packageSpec
    gofer: gofer.
  resolvedReference := references last asMetacelloCachingResolvedReference.
  mcVersion := resolvedReference version.
  (loadedVersionInfos := self ancestorsFor: packageSpec) ~~ nil
    ifTrue: [ 
      loadedVersionInfos
        do: [ :info | 
          info name = mcVersion info name
            ifTrue: [ 
              | spc |
              "package already loaded, don't load again"
              spc := packageSpec copy.
              spc file: info name.
              (MetacelloIgnorePackageLoaded signal: spc)
                ifFalse: [ ^ nil ] ] ] ].
  ^ resolvedReference!

----- Method: MetacelloCommonMCSpecLoader>>resolvePackageSpecReferences:gofer: (in category 'private') -----
resolvePackageSpecReferences: packageSpec gofer: gofer

	|  versionReference references localGofer |
	localGofer := gofer.
	self hasRepositoryOverrides not
		ifTrue: [
			packageSpec repositorySpecs notEmpty
				ifTrue: [ 
					localGofer := MetacelloGofer new.
					(self repositoriesFrom: packageSpec repositorySpecs) do: [:repo | localGofer repository: repo ]]].
	(packageSpec getFile == nil or: [ self shouldDisablePackageCache ])
		ifTrue: [ 
			"don't use package-cache when trying to get latest version"
			localGofer disablePackageCache ].
	versionReference := packageSpec goferLoaderReference.
	references := versionReference resolveAllWith: localGofer.
	localGofer enablePackageCache.
	^references!

----- Method: MetacelloCommonMCSpecLoader>>retryingResolvePackageSpecReferences:gofer: (in category 'private') -----
retryingResolvePackageSpecReferences: packageSpec gofer: gofer
    | retryCount references repositoryError |
    retryCount := 0.
    references := #().
    [ references isEmpty and: [ retryCount < 3 ] ]
        whileTrue: [ 
            retryCount > 0
                ifTrue: [ 
                    Transcript
                        cr;
                        show: '...RETRY->' , packageSpec file ].
            references := [ self resolvePackageSpecReferences: packageSpec gofer: gofer ]
                on: Error , GoferRepositoryError
                do: [ :ex | 
                    self class retryPackageResolution
                        ifFalse: [ ex pass ].
                    retryCount >= 2
                        ifTrue: [ 
                            (ex isKindOf: GoferRepositoryError)
                                ifTrue: [ 
                                    "ignore repository errors at this point, in case an alternate repository is in the list "
                                    Transcript
                                        cr;
                                        show: 'gofer repository error: ' , ex description printString , '...ignoring'.
                                    repositoryError := ex.
                                    ex resume: #() ]
                                ifFalse: [ ex pass ] ].
                    ex return: #() ].
            retryCount := retryCount + 1 ].
    references isEmpty
        ifTrue: [ 
            Transcript
                cr;
                show: '...FAILED->' , packageSpec file.
            (MetacelloPackageSpecResolutionError new
                packageSpec: packageSpec;
                repositories: gofer repositories;
                repositoryError: repositoryError;
                yourself) signal ].
    ^ references!

----- Method: MetacelloCommonMCSpecLoader>>shouldDisablePackageCache (in category 'accessing') -----
shouldDisablePackageCache

	disablePackageCache == nil ifTrue: [ disablePackageCache := false ].
	^ disablePackageCache!

----- Method: MetacelloCommonMCSpecLoader>>shouldDisablePackageCache: (in category 'accessing') -----
shouldDisablePackageCache: anObject
	disablePackageCache := anObject!

MetacelloCommonMCSpecLoader subclass: #MetacelloFetchingMCSpecLoader
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

MetacelloFetchingMCSpecLoader subclass: #MetacelloEnsureFetchingMCSpecLoader
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloEnsureFetchingMCSpecLoader>>ensureSpecLoader (in category 'accessing') -----
ensureSpecLoader
	^ self!

----- Method: MetacelloEnsureFetchingMCSpecLoader>>scheduleFetchFor:cachedReference: (in category 'private') -----
scheduleFetchFor: packageSpec cachedReference: reference
  "reference already in the cache during fetch ...schedule a load directive for reference, so ensured load will come from cache"

  ^ self
    scheduleFetchFor: packageSpec
    reference: reference
    message:
      'Fetched -> (cached) ' , reference name , ' --- '
        , reference repository repositoryDescription , ' --- '
        , reference repository description!

----- Method: MetacelloEnsureFetchingMCSpecLoader>>scheduleFetchFor:nearestReference: (in category 'private') -----
scheduleFetchFor: packageSpec nearestReference: reference
  "latest version in repository already matches the cached reference...schedule a load directive for reference, so ensured load will come from cache"

  ^ self
    scheduleFetchFor: packageSpec
    reference: reference
    message:
      'Fetched -> (nearest) ' , reference name , ' --- '
        , reference repository repositoryDescription , ' --- '
        , reference repository description!

----- Method: MetacelloFetchingMCSpecLoader>>actionLabel (in category 'accessing') -----
actionLabel

	^'Fetching '!

----- Method: MetacelloFetchingMCSpecLoader>>ancestorsFor: (in category 'versionInfo') -----
ancestorsFor: packageSpec

	^self loadData
		ancestorsFor: packageSpec 
		ifAbsent: [ super ancestorsFor: packageSpec ]!

----- Method: MetacelloFetchingMCSpecLoader>>atomicLoadPackageSpecs:repositories: (in category 'private') -----
atomicLoadPackageSpecs: packageSpecs repositories: repositories

	self loaderPolicy 
		pushAtomicLoadDirectivesDuring: [ super linearLoadPackageSpecs: packageSpecs repositories: repositories ]
		for: self!

----- Method: MetacelloFetchingMCSpecLoader>>cacheRepository (in category 'accessing') -----
cacheRepository

	^self loaderPolicy cacheRepository!

----- Method: MetacelloFetchingMCSpecLoader>>currentVersionInfoFor: (in category 'versionInfo') -----
currentVersionInfoFor: packageSpec

	^self loadData
		currentVersionInfoFor: packageSpec 
		ifAbsent: [ super currentVersionInfoFor: packageSpec ]!

----- Method: MetacelloFetchingMCSpecLoader>>doLoad (in category 'actions') -----
doLoad

	self loaderPolicy copy load!

----- Method: MetacelloFetchingMCSpecLoader>>ensureSpecLoader (in category 'accessing') -----
ensureSpecLoader
	^ (MetacelloEnsureFetchingMCSpecLoader on: self spec)
		shouldDisablePackageCache: self shouldDisablePackageCache;
		loaderPolicy: self loaderPolicy; "explicitly share the loaderPolicy"
		yourself!

----- Method: MetacelloFetchingMCSpecLoader>>ensuredMap (in category 'accessing') -----
ensuredMap

	^self loaderPolicy ensuredMap!

----- Method: MetacelloFetchingMCSpecLoader>>explicitLoadPackageSpecs:repositories: (in category 'private') -----
explicitLoadPackageSpecs: packageSpecs repositories: repositories
	
	| directive |
	directive := self loaderPolicy 
		pushExplicitLoadDirectivesDuring: [ super linearLoadPackageSpecs: packageSpecs repositories: repositories ]
		for: self.
	directive explicitLoadWithPolicy: self loaderPolicy.!

----- Method: MetacelloFetchingMCSpecLoader>>linearLoadPackageSpec:gofer: (in category 'actions') -----
linearLoadPackageSpec: packageSpec gofer: gofer
  MetacelloPlatform current
    do: [ 
      | references nearestReference cachedReference externalReference mcVersion loadedVersionInfos |
      cachedReference := nil.
      packageSpec
        searchCacheRepositoryForPackage: [ 
          "check to see if mcz file is already in cacheRepository"
          cachedReference := self
            resolvePackageSpec: packageSpec
            cachedGofer: self loaderPolicy cacheGofer.
          (cachedReference ~~ nil and: [ packageSpec getFile ~~ nil ])
            ifTrue: [ 
              cachedReference name = packageSpec file
                ifTrue: [ 
                  "exact match between packageSpec file and cache"
                  ^ self
                    scheduleFetchFor: packageSpec
                    cachedReference: cachedReference ] ] ].
      references := self
        retryingResolvePackageSpecReferences: packageSpec
        gofer: gofer.	"look up mcz file"
      nearestReference := references last asMetacelloCachingResolvedReference.
      (cachedReference ~~ nil
        and: [ cachedReference name = nearestReference name ])
        ifTrue: [ 
          "latest reference in repository matches cachedReference ... "
          ^ self
            scheduleFetchFor: packageSpec
            nearestReference: nearestReference ].
      (self ignoreImage not
        and: [ (loadedVersionInfos := self ancestorsFor: packageSpec) ~~ nil ])
        ifTrue: [ 
          "If the mcz is already loaded into the image, no need to copy"
          loadedVersionInfos
            do: [ :info | 
              info name = nearestReference name
                ifTrue: [ 
                  | spc |
                  spc := packageSpec copy.
                  spc file: info name.
                  (MetacelloIgnorePackageLoaded signal: spc)
                    ifFalse: [ ^ self ] ] ] ].
      externalReference := (references
        select: [ :ref | ref name = nearestReference name ]) first
        asMetacelloCachingResolvedReference.
      self repositoryMap
        at: externalReference name
        put: externalReference repository.
      (self
        resolveDependencies: externalReference
        nearest: nearestReference
        into: (OrderedCollection with: nearestReference))
        do: [ :reference | 
          | pSpec l |
          mcVersion := reference version.
          (l := (GoferVersionReference name: reference name)
            resolveAllWith: self loaderPolicy cacheGofer) isEmpty
            ifTrue: [ 
              self cacheRepository storeVersion: mcVersion.
              reference == nearestReference
                ifTrue: [ pSpec := packageSpec ]
                ifFalse: [ 
                  pSpec := packageSpec project packageSpec.
                  pSpec name: mcVersion package name ].
              self loadData
                addVersion: mcVersion
                versionInfo: mcVersion info
                resolvedReference: reference
                packageSpec: pSpec ] ].
      self scheduleFetchFor: packageSpec externalReference: externalReference ]
    displaying: 'Fetching ' , packageSpec file!

----- Method: MetacelloFetchingMCSpecLoader>>linearLoadPackageSpecs:repositories: (in category 'private') -----
linearLoadPackageSpecs: packageSpecs repositories: repositories
	
	self loaderPolicy 
		pushLinearLoadDirectivesDuring: [ super linearLoadPackageSpecs: packageSpecs repositories: repositories ]
		 for: self!

----- Method: MetacelloFetchingMCSpecLoader>>loadData (in category 'accessing') -----
loadData

	^self loaderPolicy loadData!

----- Method: MetacelloFetchingMCSpecLoader>>loadDirective (in category 'accessing') -----
loadDirective

	^self loaderPolicy loadDirective!

----- Method: MetacelloFetchingMCSpecLoader>>loadingSpecLoader (in category 'accessing') -----
loadingSpecLoader

	^(MetacelloLoadingMCSpecLoader on: self spec)
		shouldDisablePackageCache: self shouldDisablePackageCache;
		loaderPolicy: self loaderPolicy copy;
		yourself!

----- Method: MetacelloFetchingMCSpecLoader>>postLoad: (in category 'doits') -----
postLoad: packageOrVersionSpec

	(MetacelloDirective postLoadSpec: packageOrVersionSpec loader: self)  addTo: self loadDirective!

----- Method: MetacelloFetchingMCSpecLoader>>preLoad: (in category 'doits') -----
preLoad: packageOrVersionSpec

	(MetacelloDirective preLoadSpec: packageOrVersionSpec loader: self) addTo: self loadDirective!

----- Method: MetacelloFetchingMCSpecLoader>>printOn: (in category 'printing') -----
printOn: aStream
	super printOn: aStream.
	aStream nextPut: $(.
	self loadDirective printOn: aStream.
	aStream nextPut: $)!

----- Method: MetacelloFetchingMCSpecLoader>>resolveDependencies:nearest:into: (in category 'private') -----
resolveDependencies: aResolvedReference nearest: nearestReference into: aCollection
  | block retryCount coll notDone |
  self flag: 'Not used, but retained to avoid upgrade issues'.
  block := [ :dependency | 
  | reference |
  reference := MetacelloCachingGoferResolvedReference
    name: dependency versionInfo name
    repository: aResolvedReference repository.
  coll add: reference.
  Transcript
    cr;
    show:
        'Fetched dependency -> ' , reference name , ' --- '
            , reference repository repositoryDescription.
  self resolveDependencies: reference nearest: reference into: coll ].
  retryCount := 0.
  notDone := true.
  coll := OrderedCollection new.
  [ notDone and: [ retryCount < 3 ] ]
    whileTrue: [ 
      retryCount > 0
        ifTrue: [ 
          Transcript
            cr;
            show: '...RETRY' ].
      [ 
      "ensure that all resolved references have cached their version while wrapped by error handler"
      aCollection do: [ :each | each version ].
      nearestReference version dependencies do: block.
      notDone := false ]
        on: Error
        do: [ :ex | 
          retryCount := retryCount + 1.
          retryCount >= 3
            ifTrue: [ ex pass ].
          coll := OrderedCollection new ] ].
  aCollection addAll: coll.
  ^ aCollection!

----- Method: MetacelloFetchingMCSpecLoader>>resolvePackageSpec:cachedGofer: (in category 'private') -----
resolvePackageSpec: packageSpec cachedGofer: gofer

	|  versionReference references |
	versionReference := packageSpec goferLoaderReference.
	(references := versionReference resolveAllWith: gofer) isEmpty 
		ifTrue: [ ^nil ].
	^references last asMetacelloCachingResolvedReference.!

----- Method: MetacelloFetchingMCSpecLoader>>scheduleFetchFor:cachedReference: (in category 'private') -----
scheduleFetchFor: packageSpec cachedReference: reference
	"reference already in the cache during fetch ...no need to schedule fetch"

	^ self!

----- Method: MetacelloFetchingMCSpecLoader>>scheduleFetchFor:externalReference: (in category 'private') -----
scheduleFetchFor: packageSpec externalReference: reference
  ^ self
    scheduleFetchFor: packageSpec
    reference: reference
    message:
      'Fetched -> ' , reference name , ' --- '
        , reference repository repositoryDescription , ' --- '
        , reference repository description!

----- Method: MetacelloFetchingMCSpecLoader>>scheduleFetchFor:nearestReference: (in category 'private') -----
scheduleFetchFor: packageSpec nearestReference: reference
	"latest version in repository already matches the cached reference...no need to schedule fetch"

	^ self!

----- Method: MetacelloFetchingMCSpecLoader>>scheduleFetchFor:reference:message: (in category 'private') -----
scheduleFetchFor: packageSpec reference: reference message: message
	self loaderPolicy resetCacheGofer.
	self preLoad: packageSpec.
	(MetacelloDirective loadPackage: packageSpec externalReference: reference loader: self) addTo: self loadDirective.
	self postLoad: packageSpec.
	Transcript
		cr;
		show: message!

MetacelloFetchingMCSpecLoader subclass: #MetacelloNullRecordingMCSpecLoader
	instanceVariableNames: 'afterLoads beforeLoads evalDoits'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloNullRecordingMCSpecLoader>>actionLabel (in category 'accessing') -----
actionLabel

	^'Recording '!

----- Method: MetacelloNullRecordingMCSpecLoader>>afterLoads (in category 'accessing') -----
afterLoads

	afterLoads == nil ifTrue: [ afterLoads := OrderedCollection new ].
	^afterLoads!

----- Method: MetacelloNullRecordingMCSpecLoader>>beforeLoads (in category 'accessing') -----
beforeLoads

	beforeLoads == nil ifTrue: [ beforeLoads := OrderedCollection new ].
	^beforeLoads!

----- Method: MetacelloNullRecordingMCSpecLoader>>currentVersionInfoFor: (in category 'versionInfo') -----
currentVersionInfoFor: packageSpec

	^self loadData
		currentVersionInfoFor: packageSpec 
		ifAbsent: [ nil ]!

----- Method: MetacelloNullRecordingMCSpecLoader>>doingLoads: (in category 'actions') -----
doingLoads: aBlock
	"escape mechanism for recording and null loaders to skip doing loaderlike things"!

----- Method: MetacelloNullRecordingMCSpecLoader>>ensureForDevelopment (in category 'testing') -----
ensureForDevelopment

	^false!

----- Method: MetacelloNullRecordingMCSpecLoader>>evalDoits (in category 'accessing') -----
evalDoits

	evalDoits == nil ifTrue: [ evalDoits := false ].
	^evalDoits!

----- Method: MetacelloNullRecordingMCSpecLoader>>evalDoits: (in category 'accessing') -----
evalDoits: aBool

	evalDoits := aBool!

----- Method: MetacelloNullRecordingMCSpecLoader>>linearLoadPackageSpec:gofer: (in category 'actions') -----
linearLoadPackageSpec: packageSpec gofer: gofer

	MetacelloPlatform current
		do:  [ | externalReference loadBlock answers fake |
			externalReference := self resolveRecordingPackageSpecReference: packageSpec gofer: gofer.
			loadBlock := [
					self preLoad: packageSpec.
					(MetacelloDirective 
						loadPackage: packageSpec 
						externalReference: externalReference 
						loader: self) addTo: self loadDirective.
					self postLoad: packageSpec ].
			(answers := packageSpec answers) notEmpty
				ifTrue: [ loadBlock valueSupplyingMetacelloAnswers: answers ]
				ifFalse: [ loadBlock value ].
			fake := packageSpec copy.
			fake name: fake file.
			self loadData 
				addVersion: fake
				versionInfo: fake
				resolvedReference: externalReference 
				packageSpec: packageSpec ]
		displaying: 'Recording ', packageSpec file!

----- Method: MetacelloNullRecordingMCSpecLoader>>loadPackageDirective:gofer: (in category 'actions') -----
loadPackageDirective: aPackageLoadDirective gofer: aGofer
	"Noop"!

----- Method: MetacelloNullRecordingMCSpecLoader>>loadPackageDirectives:gofer: (in category 'actions') -----
loadPackageDirectives: pkgLoads gofer: aGofer
	"Noop"!

----- Method: MetacelloNullRecordingMCSpecLoader>>loadedPackages (in category 'accessing') -----
loadedPackages

	| packages |
	packages := OrderedCollection new.
	self loadDirective packageDirectivesDo: [:directive | packages add: directive file ].
	^packages!

----- Method: MetacelloNullRecordingMCSpecLoader>>loadedRepositories (in category 'accessing') -----
loadedRepositories

	| repos |
	repos := OrderedCollection new.
	self repositoryMap values collect: [:coll | repos addAll: coll ].
	^repos!

----- Method: MetacelloNullRecordingMCSpecLoader>>loadingSpecLoader (in category 'accessing') -----
loadingSpecLoader

	^self!

----- Method: MetacelloNullRecordingMCSpecLoader>>packages (in category 'accessing') -----
packages

	| packages |
	packages := OrderedCollection new.
	self loadDirective packageDirectivesDo: [:directive | packages add: directive spec ].
	^packages!

----- Method: MetacelloNullRecordingMCSpecLoader>>postLoad: (in category 'doits') -----
postLoad: packageOrVersionSpec

	self evalDoits ifFalse: [ ^self ].
	packageOrVersionSpec postLoadDoItBlock ~~ nil
		ifTrue: [ self afterLoads add: packageOrVersionSpec printString, ' load' ].
	super postLoad: packageOrVersionSpec!

----- Method: MetacelloNullRecordingMCSpecLoader>>preLoad: (in category 'doits') -----
preLoad: packageOrVersionSpec

	self evalDoits ifFalse: [ ^self ].
	packageOrVersionSpec preLoadDoItBlock ~~ nil
		ifTrue: [ self beforeLoads add: packageOrVersionSpec printString, ' load' ].
	super preLoad: packageOrVersionSpec!

----- Method: MetacelloNullRecordingMCSpecLoader>>recordingSpecLoader (in category 'accessing') -----
recordingSpecLoader

	^self!

----- Method: MetacelloNullRecordingMCSpecLoader>>resolvePackageSpecReferences:gofer: (in category 'private') -----
resolvePackageSpecReferences: packageSpec gofer: gofer

	|  versionReference references localGofer |
	localGofer := gofer.
	self hasRepositoryOverrides not
		ifTrue: [
			packageSpec repositorySpecs notEmpty
				ifTrue: [ 
					localGofer := MetacelloGofer new.
					(self repositoriesFrom: packageSpec repositorySpecs) do: [:repo | localGofer repository: repo ]]].
	(packageSpec getFile == nil or: [ self shouldDisablePackageCache ])
		ifTrue: [ 
			"don't use package-cache when trying to get latest version"
			localGofer disablePackageCache ].
	versionReference := packageSpec goferLoaderReference.
	references := versionReference resolveAllWith: localGofer.
	localGofer enablePackageCache.
	^references!

----- Method: MetacelloNullRecordingMCSpecLoader>>resolveRecordingPackageSpecReference:gofer: (in category 'private') -----
resolveRecordingPackageSpecReference: packageSpec gofer: gofer
  | externalPackageReference |
  externalPackageReference := packageSpec file == nil
    ifTrue: [ GoferPackageReference name: packageSpec name ]
    ifFalse: [ GoferResolvedReference name: packageSpec file repository: nil ].
  packageSpec repositorySpecs isEmpty
    ifTrue: [ 
      self repositoryMap
        at: externalPackageReference packageName
        put:
          (gofer repositories
            reject: [ :repo | repo = MetacelloPlatform current defaultPackageCache ]) ]
    ifFalse: [ 
      self repositoryMap
        at: externalPackageReference packageName
        put:
          (packageSpec repositorySpecs collect: [ :repoSpec | repoSpec createRepository ]) ].
  ^ externalPackageReference!

MetacelloCommonMCSpecLoader subclass: #MetacelloLoadingMCSpecLoader
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloLoadingMCSpecLoader>>actionLabel (in category 'accessing') -----
actionLabel

	^'Loading '!

----- Method: MetacelloLoadingMCSpecLoader>>copySpec:from:to: (in category 'development support') -----
copySpec: pkgSpec from: repositorySpecs to: repository

	| gofer |
	gofer := MetacelloGofer new.
	(self repositoriesFrom: repositorySpecs) do: [:repo | gofer repository: repo ].
	^self copySpec: pkgSpec with: gofer to: repository!

----- Method: MetacelloLoadingMCSpecLoader>>copySpec:with:to: (in category 'development support') -----
copySpec: pkgSpec with: gofer to: aRepository

	| repository resolvedReference |
	[resolvedReference := pkgSpec goferLoaderReference resolveWith: gofer]
		on: Error
		do: [:ignored | ^nil ].
	repository := MCRepositoryGroup default repositories
		detect: [ :each | each = aRepository ]
		ifNone: [ aRepository ].
	repository storeVersion: resolvedReference version.
	^resolvedReference repository!

----- Method: MetacelloLoadingMCSpecLoader>>doLoad (in category 'actions') -----
doLoad
	"NOOP"!

----- Method: MetacelloLoadingMCSpecLoader>>fetchingSpecLoader (in category 'accessing') -----
fetchingSpecLoader

	^(MetacelloFetchingMCSpecLoader on: self spec)
		shouldDisablePackageCache: self shouldDisablePackageCache;
		loaderPolicy: self loaderPolicy copy;
		yourself!

----- Method: MetacelloLoadingMCSpecLoader>>goferCommitBranchPackage:using:commitMessage: (in category 'development support') -----
goferCommitBranchPackage: branchName using: repositorySpecs commitMessage: commitMessage
	| gofer repoSpecs wc |
	repoSpecs := self spec repositorySpecs notEmpty
		ifTrue: [ self spec repositorySpecs ]
		ifFalse: [ repositorySpecs ].
	gofer := MetacelloGofer new.
	gofer disablePackageCache.
	wc := self spec workingCopy.
	repositorySpecs
		do: [ :repoSpec | 
			| repo |
			repo := repoSpec createRepository.
			(wc possiblyNewerVersionsIn: repo) notEmpty
				ifTrue: [ 
					self
						notify:
							'There are possibly newer versions of the package ' , self spec name printString , ' in the repository '
								, repo description printString
								, '. Cancel and manually merge if you want to pick up the changes from the later version.' ].
			gofer repository: repo ].
	gofer package: self spec name.
	[ gofer interactiveCommit ]
		on: MCVersionNameAndMessageRequest
		do: [ :ex | 
			| ref |
			ref := GoferVersionReference name: ex suggestedName.
			ex
				resume:
					{(ref packageName , '.' , branchName , '-' , ref author , '.' , ref versionNumber printString).
					commitMessage} ].
	^ true!

----- Method: MetacelloLoadingMCSpecLoader>>goferCommitPackageUsing:commitMessage: (in category 'development support') -----
goferCommitPackageUsing: repositorySpecs commitMessage: commitMessage

	| gofer repoSpecs wc |
	repoSpecs := self spec repositorySpecs notEmpty
				ifTrue: [ self spec repositorySpecs ]
				ifFalse: [ repositorySpecs ].
	gofer := MetacelloGofer new.
	gofer disablePackageCache.
	wc := self spec workingCopy.
	repositorySpecs do: [:repoSpec | | repo |
		repo := repoSpec createRepository.
		(wc possiblyNewerVersionsIn: repo) notEmpty
			ifTrue: [ self notify: 'There are possibly newer versions of the package ', self spec name printString, ' in the repository ', repo description printString, '. Cancel and manually merge if you want to pick up the changes from the later version.' ].
		gofer repository: repo ].
	gofer package: self spec name.
	gofer commit: commitMessage.
	^true!

----- Method: MetacelloLoadingMCSpecLoader>>latestPackage:fromRepository: (in category 'packages') -----
latestPackage: aString fromRepository: repositorySpecs

	| gofer |
	gofer := MetacelloGofer new.
	gofer disablePackageCache.
	(self repositoriesFrom: repositorySpecs) do: [:repo | gofer repository: repo ].
	^([(GoferPackageReference name: aString) resolveWith: gofer]
		on: Error
		do: [:ignored | ^ nil ]) name!

----- Method: MetacelloLoadingMCSpecLoader>>linearLoadPackageSpec:gofer: (in category 'private') -----
linearLoadPackageSpec: packageSpec gofer: gofer
  MetacelloPlatform current
    do: [ 
      | loadBlock goferLoad answers resolvedReference repo |
      resolvedReference := self resolvePackageSpec: packageSpec gofer: gofer.
      resolvedReference isNil
        ifTrue: [ 
          "Package version already loaded into image"
          ^ self ].
      loadBlock := [ 
      self preLoad: packageSpec.
      goferLoad := MetacelloGoferLoad on: MetacelloGofer new.
      goferLoad addResolved: resolvedReference.
      goferLoad execute.
      MetacelloPlatform current clearCurrentVersionCache.
      self postLoad: packageSpec ].
      (answers := packageSpec answers) notEmpty
        ifTrue: [ loadBlock valueSupplyingMetacelloAnswers: answers ]
        ifFalse: [ loadBlock value ].
      repo := resolvedReference repository.
      self hasRepositoryOverrides
        ifTrue: [ 
          repo := self loaderPolicy repositoryMap
            at: resolvedReference name
            ifAbsent: [ resolvedReference repository ].
          resolvedReference workingCopy repositoryGroup addRepository: repo ]
        ifFalse: [ 
          resolvedReference workingCopy repositoryGroup
            addRepository: resolvedReference repository ].
      Transcript
        cr;
        show:
            'Loaded -> ' , resolvedReference name , ' --- ' , repo repositoryDescription
                , ' --- ' , resolvedReference repository description ]
    displaying: 'Loading ' , packageSpec file!

----- Method: MetacelloLoadingMCSpecLoader>>packagesNeedSavingUsing:into: (in category 'development support') -----
packagesNeedSavingUsing: repositorySpecs into: aCollection

	| wc repoSpecs repo |
	(wc := self spec workingCopy) == nil ifTrue: [ ^self ].
	(wc ancestry ancestors notEmpty and: [ wc modified not])
		ifTrue: [ ^self ].
	repoSpecs := self spec repositorySpecs notEmpty
				ifTrue: [ self spec repositorySpecs ]
				ifFalse: [ repositorySpecs ].
	repo := (self spec getFile == nil or: [ wc ancestry ancestors isEmpty ])
		ifTrue: [ (self repositoriesFrom: repoSpecs ignoreOverrides: true) first ]
		ifFalse: [
			([ self resolveSpec: self spec from: repoSpecs ] 
				on: Error 
				do: [:ignored | ^self ]) repository ].
	aCollection add: self spec -> repo!

----- Method: MetacelloLoadingMCSpecLoader>>postLoad: (in category 'doits') -----
postLoad: packageOrVersionSpec

	| block |
	(block := packageOrVersionSpec postLoadDoItBlock) ~~ nil
		ifTrue: [ block valueWithPossibleArgs: { self. packageOrVersionSpec. } ]!

----- Method: MetacelloLoadingMCSpecLoader>>preLoad: (in category 'doits') -----
preLoad: packageOrVersionSpec

	| block |
	(block := packageOrVersionSpec preLoadDoItBlock) ~~ nil
		ifTrue: [ block valueWithPossibleArgs: { self. packageOrVersionSpec. } ]!

----- Method: MetacelloLoadingMCSpecLoader>>repositoryFor:from: (in category 'development support') -----
repositoryFor: pkgSpec from: repositorySpecs

	^([self resolveSpec: pkgSpec from: repositorySpecs]
		on: Error
		do: [:ignored | ^nil ]) repository!

----- Method: MetacelloLoadingMCSpecLoader>>repositoryFor:with: (in category 'development support') -----
repositoryFor: pkgSpec with: gofer

	^([self resolveSpec: pkgSpec with: gofer]
		on: Error
		do: [:ignored | ^nil ]) repository!

----- Method: MetacelloLoadingMCSpecLoader>>resolveSpec:from: (in category 'development support') -----
resolveSpec: pkgSpec from: repositorySpecs

	| gofer |
	gofer := MetacelloGofer new.
	gofer disablePackageCache.
	(self repositoriesFrom: repositorySpecs ignoreOverrides: true) 
		do: [:repo | gofer repository: repo ].
	^self resolveSpec: pkgSpec with: gofer!

----- Method: MetacelloLoadingMCSpecLoader>>resolveSpec:with: (in category 'development support') -----
resolveSpec: pkgSpec with: gofer

	^pkgSpec goferLoaderReference resolveWith: gofer!

----- Method: MetacelloLoadingMCSpecLoader>>savePackageUsing: (in category 'development support') -----
savePackageUsing: repositorySpecs

	| wc repo repoSpecs newVersion |
	(wc := self spec workingCopy) == nil ifTrue: [ ^false ].
	(wc ancestry ancestors notEmpty and: [ wc modified not])
		ifTrue: [ ^false ].
	repoSpecs := self spec repositorySpecs notEmpty
				ifTrue: [ self spec repositorySpecs ]
				ifFalse: [ repositorySpecs ].
	(self spec getFile == nil or: [ wc ancestry ancestors isEmpty ])
		ifTrue: [ repo := (self repositoriesFrom: repoSpecs ignoreOverrides: true) first ]
		ifFalse: [
			[ 	| newer |
				repo := (self resolveSpec: self spec from: repoSpecs) repository.
				newer := wc possiblyNewerVersionsIn: repo.
				newer isEmpty not 
					ifTrue: [
						(MetacelloPlatform current confirm: 'CAUTION!! These versions in the repository may be newer:', 
							String cr, newer printString, String cr,
							'Do you really want to save this version?') ifFalse: [ ^false ]] ] 
				on: Error 
				do: [:ignored | ^false ] ].
	(newVersion :=  MetacelloPlatform current newVersionForWorkingCopy: wc) == nil ifTrue: [ ^false ].
	repo storeVersion: newVersion.
	^true!

----- Method: MetacelloBaselineConstructor>>projectClass (in category '*metacello-mc-accessing') -----
projectClass
    ^ MetacelloMCBaselineProject!

----- Method: MetacelloMemberSpec>>addToMetacelloPackages: (in category '*metacello-mc') -----
addToMetacelloPackages: aMetacelloPackagesSpec

	aMetacelloPackagesSpec addMember: self!

----- Method: MetacelloMemberSpec>>addToMetacelloRepositories: (in category '*metacello-mc') -----
addToMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: self!

----- Method: MetacelloMemberSpec>>mergeIntoMetacelloPackages: (in category '*metacello-mc') -----
mergeIntoMetacelloPackages: aMetacelloPackagesSpec

	aMetacelloPackagesSpec addMember: self!

----- Method: MetacelloMemberSpec>>mergeIntoMetacelloRepositories: (in category '*metacello-mc') -----
mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: self!

----- Method: MetacelloMemberSpec>>removeFromMetacelloPackages: (in category '*metacello-mc') -----
removeFromMetacelloPackages: aMetacelloPackagesSpec

	aMetacelloPackagesSpec addMember: self!

----- Method: MetacelloMemberSpec>>removeFromMetacelloRepositories: (in category '*metacello-mc') -----
removeFromMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: self!

----- Method: MCDictionaryRepository>>asRepositorySpecFor: (in category '*metacello-mc') -----
asRepositorySpecFor: aMetacelloMCProject

	| desc |
	desc := self description.
	desc ifNil: [ desc := 'dictionary://Metacello_Dictionary' ].
	^(aMetacelloMCProject repositorySpec)
		description:  desc;
	 	type: 'dictionary';
		yourself!

----- Method: MCDictionaryRepository>>cacheReferences (in category '*metacello-mc') -----
cacheReferences
	^ false!

----- Method: MCDictionaryRepository>>versionInfoFromVersionNamed: (in category '*metacello-mc') -----
versionInfoFromVersionNamed: aString

	| versions |
	versions := self dictionary values select: [:version | version info name beginsWith: aString ].
	versions isEmpty ifTrue: [ ^ nil ].
	versions := versions asSortedCollection: [ :a :b |
		([ (a info name copyAfterLast: $.) asNumber ] on: Error do: [:ex | ex return: 0 ]) <= 
			([ (b info name copyAfterLast: $.) asNumber ] on: Error do: [:ex | ex return: 0 ]) ].
	^ versions last info!

----- Method: String>>addToMetacelloRepositories: (in category '*metacello-mc') -----
addToMetacelloRepositories: aMetacelloRepositoriesSpec

	| spec |
	spec := 
		(aMetacelloRepositoriesSpec project repositorySpec)
			description: self;
			yourself.
	aMetacelloRepositoriesSpec addMember: 
		(aMetacelloRepositoriesSpec addMember 
			name: spec name;
			spec: spec;
			yourself)!

----- Method: String>>fetchRequiredForMetacelloMCVersion: (in category '*metacello-mc') -----
fetchRequiredForMetacelloMCVersion: aMetacelloMCVersion

	^aMetacelloMCVersion doFetchRequiredFromArray: (Array with: self).!

----- Method: String>>loadRequiredForMetacelloMCVersion: (in category '*metacello-mc') -----
loadRequiredForMetacelloMCVersion: aMetacelloMCVersion

	^aMetacelloMCVersion doLoadRequiredFromArray: (Array with: self).!

----- Method: String>>mergeIntoMetacelloRepositories: (in category '*metacello-mc') -----
mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec

	| spec |
	spec := 
		(aMetacelloRepositoriesSpec project repositorySpec)
			description: self;
			yourself.
	aMetacelloRepositoriesSpec addMember: 
		(aMetacelloRepositoriesSpec mergeMember 
			name: spec name;
			spec: spec;
			yourself)!

----- Method: String>>packageFileSpecFor: (in category '*metacello-mc') -----
packageFileSpecFor: aMetacelloPackagesSpec

	^(aMetacelloPackagesSpec project packageSpec)
			file: self;
			yourself!

----- Method: String>>recordRequiredForMetacelloMCVersion: (in category '*metacello-mc') -----
recordRequiredForMetacelloMCVersion: aMetacelloMCVersion

	^aMetacelloMCVersion doRecordRequiredFromArray: (Array with: self).!

----- Method: String>>removeFromMetacelloRepositories: (in category '*metacello-mc') -----
removeFromMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: 
		(aMetacelloRepositoriesSpec removeMember 
			name: self;
			yourself)!

----- Method: String>>resolvePackageSpecsNamedForMetacelloMCVersion:visited:ifAbsent: (in category '*metacello-mc') -----
resolvePackageSpecsNamedForMetacelloMCVersion: aMetacelloMCVersion visited: visited ifAbsent: aBlock
    ^ aMetacelloMCVersion
        allPackagesForSpecs: {(aMetacelloMCVersion packageNamed: self ifAbsent: aBlock)}
        visited: visited!

----- Method: String>>setLoadsInMetacelloProject: (in category '*metacello-mc') -----
setLoadsInMetacelloProject: aMetacelloPackageSpec

	aMetacelloPackageSpec setLoads: { self }.
!

----- Method: GoferPackageReference>>metacelloPackageNameWithBranch (in category '*metacello-mc') -----
metacelloPackageNameWithBranch
    "answer array with package name and package name with branch name .. no branch name"

    ^ {(self packageName).
    (self packageName)}!

GoferPackageReference subclass: #MetacelloGoferPackage
	instanceVariableNames: 'packageFilename version workingCopy'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Gofer'!

----- Method: MetacelloGoferPackage class>>name:packageFilename: (in category 'instance creation') -----
name: aString packageFilename: packageFilename
	^ self basicNew initializeName: aString packageFilename: packageFilename!

----- Method: MetacelloGoferPackage class>>packageFileName:matchesPackageName: (in category 'package name matching') -----
packageFileName: pkgFileName matchesPackageName: wcPkgName
  ^ (pkgFileName beginsWith: wcPkgName)
    ifTrue: [ 
      pkgFileName size = wcPkgName size
        or: [ 
          (pkgFileName at: wcPkgName size + 1) = $-
            or: [ 
              (pkgFileName at: wcPkgName size + 1) = $.
                or: [ (pkgFileName at: wcPkgName size + 1) isDigit ] ] ] ]
    ifFalse: [ 
      pkgFileName size >= wcPkgName size
        ifTrue: [ ^ false ].
      (wcPkgName beginsWith: pkgFileName)
        ifFalse: [ ^ false ].
      ^ (wcPkgName at: pkgFileName size + 1) = $. ]!

----- Method: MetacelloGoferPackage>>ancestors (in category 'querying') -----
ancestors

	| wc |
	(wc := self workingCopy) ~~ nil
		ifTrue: [ 
			wc ancestry ancestors isEmpty not
				ifTrue: [ ^wc ancestry ancestors ]].
	^nil!

----- Method: MetacelloGoferPackage>>currentVersionInfo (in category 'querying') -----
currentVersionInfo

	| wc |
	(wc := self workingCopy) ~~ nil
		ifTrue: [ 
			wc ancestry ancestors isEmpty not
				ifTrue: [ ^wc ancestry ancestors first ]].
	^nil!

----- Method: MetacelloGoferPackage>>findWorkingCopy (in category 'private') -----
findWorkingCopy
	"Answer a working copy, or nil if the package is not loaded."

	| wcs |
	wcs := MCWorkingCopy allManagers select: [ :each | self matchesWorkingCopy: each ].
	wcs isEmpty ifTrue: [ ^nil ].
	^wcs detectMax: [:ea | ea package name size ]!

----- Method: MetacelloGoferPackage>>initializeName:packageFilename: (in category 'initialization') -----
initializeName: aString packageFilename: packagefilename

	name := aString.
	packageFilename := packagefilename!

----- Method: MetacelloGoferPackage>>matches: (in category 'private') -----
matches: aLoadableReference
  | pFilename |
  ((pFilename := self packageFilename) == nil
    or: [ self name = self packageFilename ])
    ifTrue: [ ^ super matches: aLoadableReference ].
  aLoadableReference name = pFilename
    ifTrue: [ ^ true ].
  (aLoadableReference name beginsWith: pFilename)
    ifFalse: [ ^ false ].
  ^ aLoadableReference matchesMetacelloGoferPackage: self!

----- Method: MetacelloGoferPackage>>matchesMetacelloGoferPackage: (in category 'private') -----
matchesMetacelloGoferPackage: aMetacelloGoferPackage
  self
    error:
      'Should not be matching a MetacelloGoferPackage with another MetacelloGoferPackage'!

----- Method: MetacelloGoferPackage>>matchesWorkingCopy: (in category 'private') -----
matchesWorkingCopy: aWorkingCopy
	"check that the working copy package name matches the package file name and that the first ancestor's package file name
	 matches the packageName"
	
	| pFilename |
	(pFilename := self packageFilename) == nil ifTrue: [ ^self error: 'cannot match working copy' ].
	(self class 
		packageFileName: pFilename 
		matchesPackageName: aWorkingCopy package name)
			ifTrue: [
				aWorkingCopy ancestry ancestors isEmpty ifTrue: [ ^true ].
				^self class 
					packageFileName: aWorkingCopy ancestry ancestors first name 
					matchesPackageName: self packageName ].
	^false!

----- Method: MetacelloGoferPackage>>packageFilename (in category 'accessing') -----
packageFilename

	^packageFilename!

----- Method: MetacelloGoferPackage>>workingCopy (in category 'accessing') -----
workingCopy
	
	workingCopy == nil ifTrue: [ workingCopy := self findWorkingCopy ].
	^workingCopy!

----- Method: MCFtpRepository>>username: (in category '*metacello-mc') -----
username: aString
	"For compatibility with MetacelloRepositorySpec"

	^ self user: aString!

----- Method: MCDirectoryRepository>>asRepositorySpecFor: (in category '*metacello-mc') -----
asRepositorySpecFor: aMetacelloMCProject
  ""

  ^ directory asRepositorySpecFor: aMetacelloMCProject!

----- Method: MCDirectoryRepository>>cacheReferences (in category '*metacello-mc') -----
cacheReferences
	^ false!

GoferCommit subclass: #MetacelloGoferCommit
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Gofer'!

----- Method: MetacelloGoferCommit>>execute: (in category 'running') -----
execute: aWorkingCopy
	| version |
	version := MetacelloPlatform current newVersionForWorkingCopy: aWorkingCopy.
	self gofer repositories
		do: [ :repository | repository storeVersion: version ]!

----- Method: MetacelloGroupSpec>>loadUsing:gofer: (in category '*metacello-mc') -----
loadUsing: aLoader gofer: gofer
	"noop"!

----- Method: MetacelloGroupSpec>>resolveToLoadableSpec (in category '*metacello-mc') -----
resolveToLoadableSpec

	^nil!

----- Method: MetacelloGroupSpec>>resolveToPackagesIn:andProjects:into:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec andProjects: andProjectsBool into: packages visited: visited
  visited
    visit: self
    doing: [ :aSpec | 
      | map |
      map := aVersionSpec packages map.
      aSpec includes
        do: [ :pkgName | 
          (aVersionSpec packageNamed: pkgName forMap: map ifAbsent: [  ])
            projectDo: [ :prj | 
              andProjectsBool
                ifTrue: [ packages at: prj name put: prj ] ]
            packageDo: [ :pkg | packages at: pkg name put: pkg ]
            groupDo: [ :grp | 
              grp
                resolveToPackagesIn: aVersionSpec
                andProjects: andProjectsBool
                into: packages
                visited: visited ] ] ]!

----- Method: MetacelloGroupSpec>>resolveToPackagesIn:andProjects:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec andProjects: andProjectsBool visited: visited
  | packages |
  packages := Dictionary new.
  self
    resolveToPackagesIn: aVersionSpec
    andProjects: andProjectsBool
    into: packages
    visited: visited.
  ^ packages values asOrderedCollection!

----- Method: MetacelloGroupSpec>>resolveToPackagesIn:into:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec into: packages visited: visited
  self
    resolveToPackagesIn: aVersionSpec
    andProjects: false
    into: packages
    visited: visited!

----- Method: MetacelloGroupSpec>>resolveToPackagesIn:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec visited: visited
  | packages |
  packages := Dictionary new.
  self
    resolveToPackagesIn: aVersionSpec
    andProjects: false
    into: packages
    visited: visited.
  ^ packages values asOrderedCollection!

----- Method: MetacelloAbstractVersionConstructor>>projectClass (in category '*metacello-mc-accessing') -----
projectClass
    ^ MetacelloMCProject!

----- Method: MetacelloAbstractPackageSpec>>file (in category '*metacello-mc-querying') -----
file 
	"MetacelloPackageSpec compatibility"
	
	^nil!

----- Method: MetacelloAbstractPackageSpec>>forceUpdatePackageSpec:using: (in category '*metacello-mc') -----
forceUpdatePackageSpec: updatedSpecs using: anMCLoader

	^self updatePackageSpec: updatedSpecs using: anMCLoader!

----- Method: MetacelloAbstractPackageSpec>>getFile (in category '*metacello-mc-querying') -----
getFile
  "MetacelloPackageSpec compatibility"

  ^ nil!

----- Method: MetacelloAbstractPackageSpec>>isPackageLoaded (in category '*metacello-mc-querying') -----
isPackageLoaded

	^false!

----- Method: MetacelloAbstractPackageSpec>>loadUsing:gofer: (in category '*metacello-mc') -----
loadUsing: aLoader gofer: gofer

	^self subclassResponsibility!

----- Method: MetacelloAbstractPackageSpec>>packagesNeedSavingVisited:using:into: (in category '*metacello-mc') -----
packagesNeedSavingVisited: visitedProjects using: repos into: aCollection
	"noop by default"!

----- Method: MetacelloAbstractPackageSpec>>repository (in category '*metacello-mc-querying') -----
repository
    self deprecated: 'Use repositories or repositorySpecs'.
    ^ nil!

----- Method: MetacelloAbstractPackageSpec>>repositorySpecs (in category '*metacello-mc') -----
repositorySpecs

	^#()!

----- Method: MetacelloAbstractPackageSpec>>resolveToAllPackagesIn:into:visited: (in category '*metacello-mc') -----
resolveToAllPackagesIn: aVersionSpec into: packages visited: visited

	visited
		visit: self
		doing: [:spec |
			self visitingWithPackages: packages.
			(spec includes, spec requires) do: [:pkgName |
				(aVersionSpec packageNamed: pkgName)
					projectDo: [:prj | 
						(prj resolveToAllPackagesIn: aVersionSpec visited: visited) do: [:pkg | 
							packages at: pkg name put: pkg ]] 
					packageDo: [:pkg | 
						packages at: pkg name put: pkg.
						(pkg resolveToAllPackagesIn: aVersionSpec visited: visited) do: [:rpkg | 
							packages at: rpkg name put: rpkg ] ] 
					groupDo: [:grp | grp resolveToAllPackagesIn: aVersionSpec into: packages  visited: visited ]]]!

----- Method: MetacelloAbstractPackageSpec>>resolveToAllPackagesIn:visited: (in category '*metacello-mc') -----
resolveToAllPackagesIn: aVersionSpec visited: visited

	| packages |
	packages := Dictionary new.
	self resolveToAllPackagesIn: aVersionSpec into: packages visited: visited.
	^packages values asOrderedCollection!

----- Method: MetacelloAbstractPackageSpec>>resolveToLoadableSpec (in category '*metacello-mc') -----
resolveToLoadableSpec

	^self!

----- Method: MetacelloAbstractPackageSpec>>resolveToPackagesIn:andProjects:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec andProjects: andProjectsBool visited: visited
  ^ self resolveToPackagesIn: aVersionSpec visited: visited!

----- Method: MetacelloAbstractPackageSpec>>resolveToPackagesIn:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec visited: visited

	^self subclassResponsibility!

----- Method: MetacelloAbstractPackageSpec>>updateForSpawnMethod: (in category '*metacello-mc') -----
updateForSpawnMethod: sourceSpec
	"This means that this spec was used in a baseline and will be used in a version .... drop all information that isn't useful"

	answers := name := requires := includes := nil!

----- Method: MetacelloAbstractPackageSpec>>updatePackageRepositoriesFor: (in category '*metacello-mc') -----
updatePackageRepositoriesFor: aVersionSpec
	"noop by default"
	
	^true!

----- Method: MetacelloAbstractPackageSpec>>updatePackageSpec:using: (in category '*metacello-mc') -----
updatePackageSpec: updatedSpecs using: anMCLoader
	"Add pkg copy to updatedSpecs if the file in current image is different from the receiver's file"!

----- Method: MetacelloAbstractPackageSpec>>version (in category '*metacello-mc-querying') -----
version 
	"MetacelloPackageSpec compatibility"
	
	^nil!

----- Method: MetacelloAbstractPackageSpec>>visitingWithPackages: (in category '*metacello-mc') -----
visitingWithPackages: packages
	"noop"!

MetacelloAbstractPackageSpec subclass: #MetacelloPackageSpec
	instanceVariableNames: 'file repositories goferPackage preLoadDoIt postLoadDoIt'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloPackageSpec>>ancestors (in category 'gofer') -----
ancestors

	^self goferPackage ancestors!

----- Method: MetacelloPackageSpec>>compareCurrentVersion:targetVersionStatus:using: (in category 'testing') -----
compareCurrentVersion: anOperator targetVersionStatus: statusIgnored using: anMCLoader

	self 
		currentPackageLoaded: [:bool | ^bool ] 
		comparing: anOperator 
		notLoaded: [:ignored | ^false ]
		using: anMCLoader!

----- Method: MetacelloPackageSpec>>compareRelativeCurrentVersion:targetVersionStatus:using: (in category 'testing') -----
compareRelativeCurrentVersion: anOperator targetVersionStatus: statusIgnored using: anMCLoader

	^self compareCurrentVersion: anOperator targetVersionStatus: statusIgnored using: anMCLoader!

----- Method: MetacelloPackageSpec>>compareWorkingCopyNamed:using: (in category 'testing') -----
compareWorkingCopyNamed: wcName using: comarisonOperator
	| fileRef wcRef |
	fileRef := GoferResolvedReference name: self file.
	wcRef := GoferResolvedReference name: wcName.
	^ wcRef compare: fileRef using: comarisonOperator!

----- Method: MetacelloPackageSpec>>configMethodBodyOn:hasName:indent: (in category 'printing') -----
configMethodBodyOn: aStream hasName: hasName indent: indent

	| hasFile hasRepositories hasPreLoadDoIt hasPostLoadDoIt hasRequiresOrIncludesOrAnswers |
	hasFile := file ~~ nil.
	hasRepositories := self repositorySpecs size > 0.
	hasPreLoadDoIt := self getPreLoadDoIt ~~ nil.
	hasPostLoadDoIt := self getPostLoadDoIt ~~ nil.
	hasRequiresOrIncludesOrAnswers := (self requires isEmpty and: [ self includes isEmpty and: [self answers isEmpty ]]) not.
	hasRequiresOrIncludesOrAnswers
		ifTrue: [ 
			self 
				configMethodBodyOn: aStream 
				hasName: hasName 
				cascading: hasFile | hasRepositories | hasPreLoadDoIt | hasPostLoadDoIt
				indent: indent ].
	self 
		configMethodOn: aStream 
		for: file 
		selector: 'file: ' 
		cascading: hasName | hasRepositories | hasPreLoadDoIt | hasPostLoadDoIt | hasRequiresOrIncludesOrAnswers 
		cascade: hasRepositories | hasPreLoadDoIt | hasPostLoadDoIt 
		indent: indent.
	hasRepositories
		ifTrue: [ 
			(self repositorySpecs size > 1)
				ifTrue: [ 
					hasName | hasFile | hasPreLoadDoIt | hasPostLoadDoIt | hasRequiresOrIncludesOrAnswers
						ifTrue: [ 
							aStream cr;
							tab: indent. ].
					aStream 
						nextPutAll: 'repositories: ['; 
						cr;
						tab: indent + 1;
						nextPutAll: 'spec'; 
						cr.
					self repositories configMethodCascadeOn: aStream indent: indent + 1.
					aStream nextPutAll: ' ]' ]
				ifFalse: [ 
					hasName | hasFile | hasPreLoadDoIt | hasPostLoadDoIt | hasRequiresOrIncludesOrAnswers
						ifTrue: [ aStream cr; tab: indent ].
					self repositories configMethodCascadeOn: aStream indent: indent ].
			hasPreLoadDoIt | hasPostLoadDoIt ifTrue: [ aStream nextPut: $; ] ].
	self 
		configMethodOn: aStream 
		for: self getPreLoadDoIt 
		selector: 'preLoadDoIt: '
		cascading: hasName | hasFile | hasRepositories | hasPostLoadDoIt | hasRequiresOrIncludesOrAnswers 
		cascade: hasPostLoadDoIt 
		indent: indent.
	self 
		configMethodOn: aStream 
		for: self getPostLoadDoIt 
		selector: 'postLoadDoIt: ' 
		cascading: hasName | hasFile | hasRepositories | hasPreLoadDoIt | hasRequiresOrIncludesOrAnswers 
		cascade: false 
		indent: indent.
	aStream nextPut: $.!

----- Method: MetacelloPackageSpec>>configMethodCascadeOn:member:last:indent: (in category 'printing') -----
configMethodCascadeOn: aStream member: aMember last: lastCascade indent: indent

	aMember methodUpdateSelector  == #remove:
		ifTrue: [ aStream  nextPutAll: 'removePackage: ', self name printString ]
		ifFalse: [ self configShortCutMethodBodyOn: aStream member: aMember indent: indent ].
	lastCascade
		ifTrue: [ aStream nextPut: $. ]
		ifFalse: [ aStream nextPut: $;; cr ]!

----- Method: MetacelloPackageSpec>>configMethodOn:indent: (in category 'printing') -----
configMethodOn: aStream indent: indent

	| hasRepositories hasPreLoadDoIt hasPostLoadDoIt hasRequiresOrIncludesOrAnswers hasFile |
	hasFile := file ~~ nil.
	hasRepositories := self repositorySpecs size > 0.
	hasPreLoadDoIt := self getPreLoadDoIt ~~ nil.
	hasPostLoadDoIt := self getPostLoadDoIt ~~ nil.
	hasRequiresOrIncludesOrAnswers := (self requires isEmpty and: [ self includes isEmpty and: [self answers isEmpty ]]) not.
	aStream tab: indent; nextPutAll: 'spec '.
	hasFile | hasRepositories | hasPreLoadDoIt | hasPostLoadDoIt | hasRequiresOrIncludesOrAnswers
		ifTrue: [
			aStream cr; tab: indent + 1; nextPutAll: 'name: ', self name printString; nextPut: $;.
			self configMethodBodyOn: aStream hasName: true indent: indent + 1 ]
		ifFalse: [
			aStream nextPutAll: 'name: ', self name printString ]!

----- Method: MetacelloPackageSpec>>configShortCutMethodBodyOn:member:indent: (in category 'printing') -----
configShortCutMethodBodyOn: aStream member: aMember indent: indent

	| hasFile hasRepositories hasPreLoadDoIt hasPostLoadDoIt hasRequiresOrIncludesOrAnswers |
	hasFile := file ~~ nil.
	hasRepositories := self repositorySpecs size > 0.
	hasPreLoadDoIt := self getPreLoadDoIt ~~ nil.
	hasPostLoadDoIt := self getPostLoadDoIt ~~ nil.
	hasRequiresOrIncludesOrAnswers := (self requires isEmpty and: [ self includes isEmpty and: [self answers isEmpty ]]) not.
	hasRepositories | hasPreLoadDoIt | hasPostLoadDoIt | hasRequiresOrIncludesOrAnswers
		ifTrue: [
			aStream 
				nextPutAll: 'package: ', self name printString, ' ';
				nextPutAll: aMember methodUpdateSelector asString, ' ['; cr.
			aStream tab: indent + 1; nextPutAll: 'spec '.
			self configMethodBodyOn: aStream hasName: false indent: indent + 2.
			aStream nextPutAll: ' ]'.
			^self ].
	aStream nextPutAll: 'package: ', self name printString.
	hasFile
		ifTrue: [ aStream nextPutAll: ' with: ', file printString ]!

----- Method: MetacelloPackageSpec>>copySpecTo: (in category 'development support') -----
copySpecTo: aRepositorySpec
	"Copy current mcz file to the repository named in aRepositorySpec"

	self loader copySpec: self from: self repositorySpecs to: aRepositorySpec createRepository!

----- Method: MetacelloPackageSpec>>currentPackageLoaded:comparing:notLoaded:using: (in category 'testing') -----
currentPackageLoaded: loadedBlock comparing: comarisonOperator notLoaded: notLoadedBlock using: anMCLoader
  "Use currentVersionInfoFor: because it involves the loader and returns versionInfo for a planned load 
	 (atomic loaders) or currently loaded package"

  | wcName vis |
  vis := anMCLoader ancestorsFor: self.
  vis notNil
    ifTrue: [ 
      | fileRef wcRef |
      self getFile == nil
        ifTrue: [ ^ loadedBlock value: false ].
      vis
        do: [ :vi | 
          wcName := vi name.
          fileRef := GoferVersionReference name: self file.
          fileRef versionNumber = 0
            ifTrue: [ 
              "a shame that GoferVersionReference doesn't have better method for recognizing a missing verion number"
              "fix for: https://github.com/dalehenrich/metacello-work/issues/185"
              ^ loadedBlock value: false ].
          wcRef := GoferVersionReference name: wcName.
          (wcRef compare: fileRef using: comarisonOperator)
            ifTrue: [ ^ loadedBlock value: true ] ].
      ^ loadedBlock value: false ].
  ^ notLoadedBlock value: true!

----- Method: MetacelloPackageSpec>>currentPackageLoaded:notLoaded:using: (in category 'testing') -----
currentPackageLoaded: loadedBlock notLoaded: notLoadedBlock using: anMCLoader
	"Use currentVersionInfoFor: because it involves the loader and returns versionInfo for a planned load 
	 (atomic loaders) or currently loaded package"

	| vis |
	vis := anMCLoader ancestorsFor: self.
	vis notNil
		ifTrue: [ 
			self getFile == nil
				ifTrue: [ ^ loadedBlock value: #() value: self file ].
			^ loadedBlock value: vis value: self file ].
	^ notLoadedBlock value
!

----- Method: MetacelloPackageSpec>>currentVersionInfo (in category 'gofer') -----
currentVersionInfo

	^self goferPackage currentVersionInfo!

----- Method: MetacelloPackageSpec>>ensureLoadUsing: (in category 'loading') -----
ensureLoadUsing: mcLoader
	self explicitLoadUsing: mcLoader ensureSpecLoader!

----- Method: MetacelloPackageSpec>>ensureLoadedForDevelopmentUsing: (in category 'loading') -----
ensureLoadedForDevelopmentUsing: mcLoader
	"noop"
	
	^true!

----- Method: MetacelloPackageSpec>>explicitLoadUsing: (in category 'loading') -----
explicitLoadUsing: mcLoader

	| wc fetchingSpecLoader |
	((wc := self workingCopy) ~~ nil and: [ wc needsSaving ]) 
		ifTrue: [ 
			(MetacelloSkipDirtyPackageLoad signal: self)
				ifTrue:  [
					Transcript cr; show: 'Skipping load of modified package: ', self file.
					^self]
				ifFalse: [Transcript cr; show: 'Load over modified package: ', self file] ].
	"fetch and explicitly load it"
	fetchingSpecLoader := mcLoader fetchingSpecLoader.
	fetchingSpecLoader
		explicitLoadPackageSpecs: (Array with: self) 
		repositories: (fetchingSpecLoader repositoriesFrom: self repositorySpecs).!

----- Method: MetacelloPackageSpec>>extractNameFromFile (in category 'private') -----
extractNameFromFile

	file == nil ifTrue: [ ^nil ].
	^(self loader nameComponentsFrom: self file) first!

----- Method: MetacelloPackageSpec>>fetch (in category 'loading') -----
fetch

	self fetchUsing: self loader!

----- Method: MetacelloPackageSpec>>fetchPackage: (in category 'loading') -----
fetchPackage: aLoaderPolicy

	self fetchUsing: 
		(self loader
			loaderPolicy: aLoaderPolicy;
			yourself)!

----- Method: MetacelloPackageSpec>>fetchUsing: (in category 'loading') -----
fetchUsing: mcLoader

	| fetchingSpecLoader |
	fetchingSpecLoader := mcLoader fetchingSpecLoader.
	fetchingSpecLoader
		linearLoadPackageSpecs: (Array with: self) 
		repositories: (fetchingSpecLoader repositoriesFrom: self repositorySpecs).!

----- Method: MetacelloPackageSpec>>file (in category 'querying') -----
file

	file == nil ifTrue: [ ^self name ].
	^file!

----- Method: MetacelloPackageSpec>>file: (in category 'accessing') -----
file: aString

	file := aString!

----- Method: MetacelloPackageSpec>>file:constructor: (in category 'construction') -----
file: aString constructor: aVersionConstructor
    aVersionConstructor fileForPackage: aString!

----- Method: MetacelloPackageSpec>>forceUpdatePackageSpec:using: (in category 'development support') -----
forceUpdatePackageSpec: updatedSpecs using: anMCLoader
	
	self updatePackageSpec: updatedSpecs force: true using: anMCLoader!

----- Method: MetacelloPackageSpec>>getFile (in category 'accessing') -----
getFile
	"raw access to iv"
	
	^file!

----- Method: MetacelloPackageSpec>>getName (in category 'accessing') -----
getName
    "raw access to iv"

    ^ name!

----- Method: MetacelloPackageSpec>>getPostLoadDoIt (in category 'querying') -----
getPostLoadDoIt

	^postLoadDoIt!

----- Method: MetacelloPackageSpec>>getPreLoadDoIt (in category 'querying') -----
getPreLoadDoIt

	^preLoadDoIt!

----- Method: MetacelloPackageSpec>>getRepositories (in category 'accessing') -----
getRepositories
    "raw access to iv"

    ^ repositories!

----- Method: MetacelloPackageSpec>>goferBranchPackage:message: (in category 'development support') -----
goferBranchPackage: branchName message: commitMessage
	"uses gofer to do commit ... non-interactive"

	| latestFile pkgSpec   |
	(file notNil and: [ (self name, '.', branchName) = self file ])
		ifTrue: [ 
			latestFile := self loader latestPackage: self file fromRepository: self repositorySpecs.
			pkgSpec := self copy.
			latestFile ~~ nil
				ifTrue: [ 
					pkgSpec file: latestFile.
					pkgSpec goferCommitPackage: commitMessage.
					^ self ] ].
	self loader goferCommitBranchPackage: branchName using: self repositorySpecs commitMessage: commitMessage!

----- Method: MetacelloPackageSpec>>goferCommitPackage: (in category 'development support') -----
goferCommitPackage: commitMessage
	"uses gofer to do commit ... non-interactive"
	
	| latestFile pkgSpec |
	^(file notNil and: [ self name = self file ])
		ifTrue: [
			latestFile := self loader latestPackage: self name fromRepository: self repositorySpecs.
			pkgSpec := self copy.
			pkgSpec file: latestFile.
			pkgSpec goferCommitPackage: commitMessage ]
		ifFalse: [ self loader goferCommitPackageUsing: self repositorySpecs commitMessage: commitMessage ]!

----- Method: MetacelloPackageSpec>>goferLoaderReference (in category 'accessing') -----
goferLoaderReference

	^file == nil 
		ifTrue: [ GoferPackageReference name: self name ]
		ifFalse: [ 
			"does Monticello-style #versionInfoFromVersionNamed: matching"
			MetacelloGoferPackage name: self name packageFilename: self file ]!

----- Method: MetacelloPackageSpec>>goferPackage (in category 'accessing') -----
goferPackage

	goferPackage == nil 
		ifTrue: [ goferPackage := MetacelloGoferPackage name: self name packageFilename: self file ].
	^goferPackage!

----- Method: MetacelloPackageSpec>>hasRepository (in category 'testing') -----
hasRepository
    ^ self repositorySpecs notEmpty!

----- Method: MetacelloPackageSpec>>includes:constructor: (in category 'construction') -----
includes: anObject constructor: aVersionConstructor
    aVersionConstructor includesForPackage: anObject!

----- Method: MetacelloPackageSpec>>includesForPackageOrdering (in category 'private') -----
includesForPackageOrdering
  ^ self includes!

----- Method: MetacelloPackageSpec>>info (in category 'accessing') -----
info
	"test compatibility method"

	^self!

----- Method: MetacelloPackageSpec>>isPackageLoaded (in category 'querying') -----
isPackageLoaded

	^self isPackageLoaded: self loader!

----- Method: MetacelloPackageSpec>>isPackageLoaded: (in category 'querying') -----
isPackageLoaded: aLoader

	^(self workingCopyNameFor: aLoader) ~~ nil!

----- Method: MetacelloPackageSpec>>load (in category 'loading') -----
load

	self explicitLoadUsing: self loader!

----- Method: MetacelloPackageSpec>>loadUsing: (in category 'loading') -----
loadUsing: mcLoader

	self loader doingLoads: [ self explicitLoadUsing: mcLoader ]!

----- Method: MetacelloPackageSpec>>loadUsing:gofer: (in category 'loading') -----
loadUsing: aLoader gofer: gofer

	^aLoader linearLoadPackageSpec: self gofer: gofer!

----- Method: MetacelloPackageSpec>>mergeMap (in category 'merging') -----
mergeMap

	| map |
	map := super mergeMap.
	map at: #file put: file.
	map at: #repositories put: self repositories.
	map at: #preLoadDoIt put: preLoadDoIt.
	map at: #postLoadDoIt put: postLoadDoIt.
	^map!

----- Method: MetacelloPackageSpec>>mergeSpec: (in category 'merging') -----
mergeSpec: anotherSpec

	| newSpec map anotherRepositories |
	newSpec := super mergeSpec: anotherSpec.
	map := anotherSpec mergeMap.
	(anotherRepositories := map at: #repositories) notEmpty
		ifTrue: [ 
			newSpec 
				repositories: (self repositories isEmpty
					ifTrue: [ anotherRepositories ]
					ifFalse: [ self repositories mergeSpec: anotherRepositories ]) ].
	^newSpec
!

----- Method: MetacelloPackageSpec>>name (in category 'querying') -----
name

	name == nil ifTrue: [ name := self extractNameFromFile ].
	^name!

----- Method: MetacelloPackageSpec>>nonOverridable (in category 'merging') -----
nonOverridable

	^super nonOverridable, #( repositories)!

----- Method: MetacelloPackageSpec>>packageSpecsInLoadOrder (in category 'loading') -----
packageSpecsInLoadOrder

	^{ self. }!

----- Method: MetacelloPackageSpec>>packagesNeedSavingVisited:using:into: (in category 'development support') -----
packagesNeedSavingVisited: visitedProjects using: repos into: aCollection

	^self loader packagesNeedSavingUsing: repos into: aCollection!

----- Method: MetacelloPackageSpec>>postCopy (in category 'copying') -----
postCopy

	super postCopy.
	goferPackage := nil.
	repositories := repositories copy.!

----- Method: MetacelloPackageSpec>>postLoadDoIt (in category 'querying') -----
postLoadDoIt

	^postLoadDoIt!

----- Method: MetacelloPackageSpec>>postLoadDoIt: (in category 'loading') -----
postLoadDoIt: anObject

	anObject setPostLoadDoItInMetacelloSpec: self!

----- Method: MetacelloPackageSpec>>postLoadDoIt:constructor: (in category 'construction') -----
postLoadDoIt: aSymbol constructor: aVersionConstructor
    aVersionConstructor postLoadDoItForPackage: aSymbol!

----- Method: MetacelloPackageSpec>>preLoadDoIt (in category 'querying') -----
preLoadDoIt

	^preLoadDoIt!

----- Method: MetacelloPackageSpec>>preLoadDoIt: (in category 'accessing') -----
preLoadDoIt: anObject

	anObject setPreLoadDoItInMetacelloSpec: self!

----- Method: MetacelloPackageSpec>>preLoadDoIt:constructor: (in category 'construction') -----
preLoadDoIt: aSymbol constructor: aVersionConstructor
    aVersionConstructor preLoadDoItForPackage: aSymbol!

----- Method: MetacelloPackageSpec>>projectDo:packageDo:groupDo: (in category 'visiting') -----
projectDo: projectBlock packageDo: packageBlock groupDo: groupBlock

	packageBlock value: self!

----- Method: MetacelloPackageSpec>>repositories (in category 'querying') -----
repositories

	repositories == nil ifTrue: [ repositories := self project repositoriesSpec ].
	^ repositories!

----- Method: MetacelloPackageSpec>>repositories: (in category 'querying') -----
repositories: anObject
	repositories := anObject!

----- Method: MetacelloPackageSpec>>repositories:constructor: (in category 'construction') -----
repositories: aBlock constructor: aVersionConstructor
    aVersionConstructor repositoriesForPackage: aBlock!

----- Method: MetacelloPackageSpec>>repository (in category 'querying') -----
repository
    self deprecated: 'Use repositories or repositorySpecs'.
    self repositorySpecs isEmpty
        ifTrue: [ ^ nil ].
    ^ self repositorySpecs first!

----- Method: MetacelloPackageSpec>>repository: (in category 'accessing') -----
repository: aStringOrMetacelloRepositorySpec

	self repositories repository: aStringOrMetacelloRepositorySpec!

----- Method: MetacelloPackageSpec>>repository:constructor: (in category 'construction') -----
repository: anObject constructor: aVersionConstructor
    aVersionConstructor repositoryForPackage: anObject!

----- Method: MetacelloPackageSpec>>repository:username:password: (in category 'accessing') -----
repository: aString username: username password: password

	self repositories repository: aString username: username password: password!

----- Method: MetacelloPackageSpec>>repository:username:password:constructor: (in category 'construction') -----
repository: aString username: username password: password constructor: aVersionConstructor
    aVersionConstructor repositoryForPackage: aString username: username password: password!

----- Method: MetacelloPackageSpec>>repositoryDescriptions (in category 'loading') -----
repositoryDescriptions
    ^ self repositorySpecs collect: [ :repoSpec | repoSpec description ]!

----- Method: MetacelloPackageSpec>>repositorySpecs (in category 'loading') -----
repositorySpecs

	^self repositories map values!

----- Method: MetacelloPackageSpec>>requires:constructor: (in category 'construction') -----
requires: anObject constructor: aVersionConstructor
    aVersionConstructor requiresForPackage: anObject!

----- Method: MetacelloPackageSpec>>resolveToPackagesIn:visited: (in category 'private') -----
resolveToPackagesIn: aVersionSpec visited: visited

	^{ self }!

----- Method: MetacelloPackageSpec>>savePackage (in category 'development support') -----
savePackage
	"Interactive save ... prompted for commit message and package name unless MCVersionNameAndMessageRequest handled"

	| latestFile pkgSpec |
	^(file notNil and: [ self name = self file ])
		ifTrue: [
			latestFile := self loader latestPackage: self name fromRepository: self repositorySpecs.
			pkgSpec := self copy.
			pkgSpec file: latestFile.
			pkgSpec savePackage ]
		ifFalse: [ self loader savePackageUsing: self repositorySpecs ]!

----- Method: MetacelloPackageSpec>>searchCacheRepositoryForPackage: (in category 'fetching') -----
searchCacheRepositoryForPackage: searchBlock
  "evaluate the <searchBlock> if you want to search for the package in a local package cache"

  "for standard mcz repositories the answer is YES!!"

  searchBlock value!

----- Method: MetacelloPackageSpec>>setPostLoadDoIt: (in category 'accessing') -----
setPostLoadDoIt: aSymbol

	postLoadDoIt := aSymbol!

----- Method: MetacelloPackageSpec>>setPreLoadDoIt: (in category 'accessing') -----
setPreLoadDoIt: aSymbol

	preLoadDoIt := aSymbol!

----- Method: MetacelloPackageSpec>>supplyingAnswers:constructor: (in category 'construction') -----
supplyingAnswers: anObject constructor: aVersionConstructor
    aVersionConstructor supplyingAnswersForPackage: anObject!

----- Method: MetacelloPackageSpec>>updateForSpawnMethod: (in category 'development support') -----
updateForSpawnMethod: sourceSpec
    "This means that this spec was used in a baseline and will be used in a version .... drop all information that isn't useful"

    | nm fl |
    nm := name.
    fl := file.
    fl == nil
        ifTrue: [ 
            "if only name has been set, then force the file to be non-nil, if any attribute besides file is set, then leave file nil"
            {answers.
            requires.
            includes.
            repositories.
            preLoadDoIt.
            postLoadDoIt} detect: [ :each | each ~~ nil ] ifNone: [ fl := name ] ].
    super updateForSpawnMethod: sourceSpec.
    file := repositories := goferPackage := preLoadDoIt := postLoadDoIt := nil.
    name := nm.
    file := fl.
    ^ file == nil!

----- Method: MetacelloPackageSpec>>updatePackageRepositories: (in category 'development support') -----
updatePackageRepositories: repositorySpecs

	| resolvedPackageRef |
	Transcript cr; show: '  Looking up version -> ', self file.
	resolvedPackageRef := self loader resolveSpec: self from: repositorySpecs.
	Transcript cr; show: 'Update repositoryGroup -> ', resolvedPackageRef name, ' ' , resolvedPackageRef repository description.
	resolvedPackageRef version workingCopy repositoryGroup addRepository: resolvedPackageRef repository!

----- Method: MetacelloPackageSpec>>updatePackageRepositoriesFor: (in category 'development support') -----
updatePackageRepositoriesFor: aVersionSpec
	"Don't update the repository unless the package is loaded in the image"
	
	self workingCopy == nil ifTrue: [ ^self ].
	self updatePackageRepositories: self repositorySpecs, aVersionSpec repositorySpecs.!

----- Method: MetacelloPackageSpec>>updatePackageSpec:force:using: (in category 'development support') -----
updatePackageSpec: updatedSpecs force: force using: anMCLoader
	"Add pkg copy to updatedSpecs if the file in current image is different from the receiver's file"

	| viName |
	(force not and: [ self getFile == nil ])
		ifTrue: [ ^ self ].	"no file explicitly specified in this spec"
	(viName := self workingCopyNameFor: anMCLoader) == nil
		ifTrue: [ ^ self ].	"no working copy"
	viName ~= self file
		ifTrue: [ 
			| spec |
			spec := self copy.
			spec file: viName.
			updatedSpecs at: spec name put: spec ]
		ifFalse: [ updatedSpecs at: self name put: #uptodate ]!

----- Method: MetacelloPackageSpec>>updatePackageSpec:using: (in category 'development support') -----
updatePackageSpec: updatedSpecs using: anMCLoader
	"Add pkg copy to updatedSpecs if the file in current image is different from the receiver's file"
	
	self updatePackageSpec: updatedSpecs force: false using: anMCLoader!

----- Method: MetacelloPackageSpec>>visitingWithPackages: (in category 'visiting') -----
visitingWithPackages: packages

	packages at: self name put: self!

----- Method: MetacelloPackageSpec>>workingCopy (in category 'gofer') -----
workingCopy

	^self goferPackage workingCopy!

----- Method: MetacelloPackageSpec>>workingCopyName (in category 'gofer') -----
workingCopyName

	| wc |
	(wc := self workingCopy) == nil ifTrue: [ ^nil ].
	wc ancestry ancestors isEmpty not
		ifTrue: [ ^wc ancestry ancestors first name ].
	^nil!

----- Method: MetacelloPackageSpec>>workingCopyNameFor: (in category 'gofer') -----
workingCopyNameFor: anMCLoader

	| vi |
	(vi := anMCLoader currentVersionInfoFor: self) == nil ifTrue: [ ^nil ].
	^vi name!

----- Method: GoferReference>>matchesMetacelloGoferPackage: (in category '*metacello-mc') -----
matchesMetacelloGoferPackage: aMetacelloGoferPackage
  | pFilename refFilename char |
  ((pFilename := aMetacelloGoferPackage packageFilename) == nil
    or: [ aMetacelloGoferPackage name = aMetacelloGoferPackage packageFilename ])
    ifTrue: [ ^ super matches: self ].
  self name = pFilename
    ifTrue: [ ^ true ].
  (self name beginsWith: pFilename)
    ifFalse: [ ^ false ].
  refFilename := self metacelloPackageNameWithBranch at: 2.
  refFilename = pFilename
    ifTrue: [ ^ true ].
  pFilename size < refFilename size
    ifTrue: [ 
      (refFilename beginsWith: pFilename)
        ifFalse: [ ^ false ].
      (char := pFilename at: pFilename size) ~= $-
        ifTrue: [ char := refFilename at: pFilename size + 1 ] ]
    ifFalse: [ 
      (pFilename beginsWith: refFilename)
        ifFalse: [ ^ false ].
      (char := refFilename at: refFilename size) ~= $-
        ifTrue: [ char := pFilename at: refFilename size + 1 ] ].
  ^ char = $. or: [ char = $- ]!

GoferLoad subclass: #MetacelloGoferLoad
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Gofer'!

----- Method: MetacelloGoferLoad>>updateCategories (in category 'private') -----
updateCategories
	MetacelloPlatform current bypassGoferLoadUpdateCategories
		ifFalse: [ super updateCategories ]!

----- Method: MetacelloGoferLoad>>updateRepositories (in category 'private') -----
updateRepositories
	"Noop for Metacello...done by loader itself"!

----- Method: BlockClosure>>valueSupplyingMetacelloAnswers: (in category '*metacello-mc') -----
valueSupplyingMetacelloAnswers: aListOfPairs
	"evaluate the block using a list of questions / answers that might be called upon to
	automatically respond to Object>>confirm: or FillInTheBlank requests"

	^ [self value] 
		on: ProvideAnswerNotification
		do: 
			[:notify | | answer caption |
			
			caption := notify messageText withSeparatorsCompacted. "to remove new lines"
			answer := aListOfPairs
				detect: 
					[:each | caption = each first or:
						[(caption includesSubstring: each first caseSensitive: false) or:
						[(each first match: caption) or:
						[(String includesSelector: #matchesRegex:) and: 
						[ [ caption matchesRegex: each first ] on: Error do: [:ignored | false ]]]]]]
					ifNone: [nil].
			answer
				ifNotNil: [notify resume: answer second]
				ifNil: 
					[ | outerAnswer |
					outerAnswer := ProvideAnswerNotification signal: notify messageText.
					outerAnswer 
						ifNil: [notify resume] 
						ifNotNil: [notify resume: outerAnswer]]]!

MetacelloSpec subclass: #MetacelloRepositorySpec
	instanceVariableNames: 'description username password type'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloRepositorySpec>>addToMetacelloRepositories: (in category 'adding') -----
addToMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: 
		(aMetacelloRepositoriesSpec addMember 
			name: self name;
			spec: self;
			yourself)!

----- Method: MetacelloRepositorySpec>>canUpgradeTo: (in category 'mc support') -----
canUpgradeTo: aMetacelloRepositorySpec
  self description = aMetacelloRepositorySpec description
    ifTrue: [ ^ true ].
  (#('github' 'gitorious' 'bitbucket') includes: self type)
    ifTrue: [ ^ self createRepository canUpgradeTo: aMetacelloRepositorySpec createRepository ].
  ^ false!

----- Method: MetacelloRepositorySpec>>configMethodCascadeOn:lastCascade: (in category 'printing') -----
configMethodCascadeOn: aStream lastCascade: lastCascade

	aStream nextPutAll: 'repository: ', self description printString.
	(self username isEmpty not or: [ self password isEmpty not ])
		ifTrue: [ aStream nextPutAll: ' username: ', self username printString, ' password: ', self password printString ].
	lastCascade ifFalse: [ aStream nextPut: $;; cr ].!

----- Method: MetacelloRepositorySpec>>configMethodOn:indent: (in category 'printing') -----
configMethodOn: aStream indent: indent

	aStream 
		tab: indent; 
		nextPutAll: 'spec '.
	self configMethodCascadeOn: aStream lastCascade: true!

----- Method: MetacelloRepositorySpec>>createRepository (in category 'mc support') -----
createRepository
  | repo |
  repo := self project createRepository: self.
  ^ self updateRepository: (MCRepositoryGroup default repositories
    detect: [ :each | each = repo ]
    ifNone: [ 
      MCRepositoryGroup default addRepository: repo.
      repo ])!

----- Method: MetacelloRepositorySpec>>description (in category 'querying') -----
description

	^description!

----- Method: MetacelloRepositorySpec>>description: (in category 'accessing') -----
description: aString

	description := aString!

----- Method: MetacelloRepositorySpec>>extractTypeFromDescription (in category 'private') -----
extractTypeFromDescription

	^MetacelloPlatform current extractTypeFromDescription: self description!

----- Method: MetacelloRepositorySpec>>hasNoLoadConflicts: (in category 'mc support') -----
hasNoLoadConflicts: aMetacelloRepositorySpec
  self description = aMetacelloRepositorySpec description
    ifTrue: [ ^ true ].
  self type = aMetacelloRepositorySpec type
    ifFalse: [ 
      "if the types are different then we don't need to create the repoitory to 
       know that there will be conflicts"
      ^ false ].
  (#('github' 'gitorious' 'bitbucket') includes: self type)
    ifTrue: [ 
      ^ self createRepository
        hasNoLoadConflicts: aMetacelloRepositorySpec createRepository ].
  ^ false!

----- Method: MetacelloRepositorySpec>>mergeIntoMetacelloRepositories: (in category 'private') -----
mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: 
		(aMetacelloRepositoriesSpec mergeMember 
			name: self name;
			spec: self;
			yourself)!

----- Method: MetacelloRepositorySpec>>mergeMap (in category 'merging') -----
mergeMap
    | map |
    map := super mergeMap.
    map at: #'description' put: description.
    map at: #'type' put: self type.
    map at: #'username' put: username.
    map at: #'password' put: password.
    ^ map!

----- Method: MetacelloRepositorySpec>>name (in category 'querying') -----
name

	^self description!

----- Method: MetacelloRepositorySpec>>password (in category 'querying') -----
password

	password == nil ifTrue: [ password := '' ].
	^password!

----- Method: MetacelloRepositorySpec>>password: (in category 'accessing') -----
password: aString

	password := aString!

----- Method: MetacelloRepositorySpec>>removeFromMetacelloRepositories: (in category 'private') -----
removeFromMetacelloRepositories: aMetacelloRepositoriesSpec

	aMetacelloRepositoriesSpec addMember: 
		(aMetacelloRepositoriesSpec removeMember 
			name: self name;
			spec: self;
			yourself)!

----- Method: MetacelloRepositorySpec>>type (in category 'querying') -----
type

	type == nil ifTrue: [ type := self extractTypeFromDescription ].
	^type!

----- Method: MetacelloRepositorySpec>>type: (in category 'accessing') -----
type: aString

	type := aString!

----- Method: MetacelloRepositorySpec>>updateRepository: (in category 'mc support') -----
updateRepository: aRepository

    (self username notNil and: [self username notEmpty]) ifTrue: [
        aRepository username: self username].
	(self password notNil and: [self password notEmpty]) ifTrue: [
        aRepository password: self password].
	^ aRepository!

----- Method: MetacelloRepositorySpec>>username (in category 'querying') -----
username

	username == nil ifTrue: [ username := '' ].
	^username!

----- Method: MetacelloRepositorySpec>>username: (in category 'accessing') -----
username: aString

	username := aString!

MetacelloVersion subclass: #MetacelloMCVersion
	instanceVariableNames: 'loaderPolicy'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Model'!

----- Method: MetacelloMCVersion>>allPackagesForSpecNamed: (in category 'querying') -----
allPackagesForSpecNamed: aStringOrArray
	"resolves list of packages associated with the named spec.
	   If the spec is a packages, answer a list including the package and the transitive closure on 
			its #requires: and #includes: fields.
	   If the spec is a project, answer a list of the packages associated with the project,
			following the transitive closure on packages reachable starting with the #loads: field.
	   If the spec is a group, answers the list of packages in the #includes: field of the group. 
			Groups in the #includes: field are expanded following the transitive closure on groups"
	"In essence, this query answers the list of all packages that would be loaded if the package 
		named <aString> were loaded."
	"If there is no spec named <aString>, answers an empty list"

	^self allPackagesForSpecNamed: aStringOrArray ifAbsent: [ ^#() ]!

----- Method: MetacelloMCVersion>>allPackagesForSpecNamed:ifAbsent: (in category 'querying') -----
allPackagesForSpecNamed: aStringOrArray ifAbsent: aBlock
	"resolves list of packages associated with the named spec.
	   If the spec is a packages, answer a list including the package and the transitive closure on 
			its #requires: and #includes: fields.
	   If the spec is a project, answer a list of the packages associated with the project,
			following the transitive closure on packages reachable starting with the #loads: field.
	   If the spec is a group, answers the list of packages in the #includes: field of the group. 
			Groups in the #includes: field are expanded following the transitive closure on groups"
	"In essence, this query answers the list of all packages that would be loaded if the package 
		named <aString> were loaded."
	"If there is no spec named <aString>, aBlock is evaluated"

	^aStringOrArray 
		resolvePackageSpecsNamedForMetacelloMCVersion: self 
		visited: MetacelloVisitedPackages new 
		ifAbsent: aBlock!

----- Method: MetacelloMCVersion>>allPackagesForSpecs:visited: (in category 'private') -----
allPackagesForSpecs: pkgSpecs visited: visited

 
	| coll |
	coll := Dictionary new.
	pkgSpecs
		do: [:pkgSpec | (pkgSpec resolveToAllPackagesIn: self spec visited: visited)
				do: [:pkg | coll at: pkg name put: pkg ]].
	^ coll values asOrderedCollection!

----- Method: MetacelloMCVersion>>cacheRepository: (in category 'accessing') -----
cacheRepository: repository 
	"by default cacheRepository is an MCDictionaryRepository"
	
	self loaderPolicy cacheRepository: repository!

----- Method: MetacelloMCVersion>>computeVersionStatus (in category 'private') -----
computeVersionStatus
	"
		#allLoadedToSpec - all projects and packages are loaded and match specification
		#loadedToSpec - all loaded projects and packages match specifications (at least one package loaded)
		#loadedMatchConstraints - all loaded projects and packages match constraints (at least one package loaded)
		#somethingLoaded - at least one package loaded
	"

	self spec computeVersionStatus: [ :status | ^ status ].
	^ #noStatus!

----- Method: MetacelloMCVersion>>currentlyLoadedClassesInVersion (in category 'querying') -----
currentlyLoadedClassesInVersion

	^self spec currentlyLoadedClassesInVersion!

----- Method: MetacelloMCVersion>>currentlyLoadedExtensionClassesInVersion (in category 'querying') -----
currentlyLoadedExtensionClassesInVersion

	^self spec currentlyLoadedExtensionClassesInVersion!

----- Method: MetacelloMCVersion>>defaultPackageNamesToLoad (in category 'querying') -----
defaultPackageNamesToLoad
	"Answer the list of packages and projects to be loaded --> packages already loaded"
	
	^ self defaultPackageNamesToLoad: self spec defaultPackageNames!

----- Method: MetacelloMCVersion>>defaultPackageNamesToLoad: (in category 'querying') -----
defaultPackageNamesToLoad: defaultList
	"Answer the list of packages and projects to be loaded: packages already loaded plust defaultList"
	
	^ self packageAndProjectNamesToLoad: defaultList loader: self loader!

----- Method: MetacelloMCVersion>>doFetchRequiredFromArray: (in category 'private') -----
doFetchRequiredFromArray: anArray

	| oldPolicy oldBypassProgress displayString |
	displayString := self versionNumber printString, ' of ', self spec projectLabel.
	Transcript cr; show: 'Fetching ', displayString, '...'.
	oldPolicy := loaderPolicy. 
	oldBypassProgress := MetacelloPlatform current bypassProgressBars.
	self loaderPolicy silently ifTrue: [ MetacelloPlatform current bypassProgressBars: true ].
	[ 	| ans |
		ans := self fetchRequiredFromArray: anArray.
		Transcript cr; show: '...finished ', self versionNumber printString.
		^ans ]
			ensure: [ 
				MetacelloPlatform current bypassProgressBars: oldBypassProgress.
				loaderPolicy := oldPolicy ]!

----- Method: MetacelloMCVersion>>doLoadRequiredFromArray: (in category 'private') -----
doLoadRequiredFromArray: anArray

	| displayString oldPolicy oldBypassProgress |
	displayString := self versionNumber printString, ' of ', self spec projectLabel.
	Transcript cr; show: 'Loading ', displayString, '...'.
	oldPolicy := loaderPolicy. 
	oldBypassProgress := MetacelloPlatform current bypassProgressBars.
	self loaderPolicy silently ifTrue: [ MetacelloPlatform current bypassProgressBars: true ].
	[	| fetchLoader |
		fetchLoader := self fetchRequiredFromArray: (self defaultPackageNamesToLoad: anArray).
		MetacelloPlatform current
			do:  [  fetchLoader doLoad ]
			displaying: 'Loading ', displayString.
		Transcript cr; show: '...finished ', self versionNumber printString.
		^fetchLoader ]
		ensure: [ 
			MetacelloPlatform current bypassProgressBars: oldBypassProgress.
			loaderPolicy := oldPolicy ]!

----- Method: MetacelloMCVersion>>doRecordRequiredFromArray: (in category 'private') -----
doRecordRequiredFromArray: anArray

	| originalLoader oldPolicy displayString oldBypassProgress |
	displayString := self versionNumber printString, ' of ', self spec projectLabel.
	Transcript cr; show: 'Recording ', displayString, '...'.
	originalLoader := self versionSpec loader.
	oldPolicy := loaderPolicy. 
	oldBypassProgress := MetacelloPlatform current bypassProgressBars.
	self loaderPolicy silently ifTrue: [ MetacelloPlatform current bypassProgressBars: true ].
	[	MetacelloPlatform current
			do:  [ | ans |
				self versionSpec loader: originalLoader recordingSpecLoader.
				ans := (self executeLoadFromArray: anArray) copy.
				Transcript cr; show: '...finished ', self versionNumber printString.
				^ans ]
			displaying: 'Recording ', displayString ]
				ensure: [
					MetacelloPlatform current bypassProgressBars: oldBypassProgress.
					self versionSpec loader: originalLoader.
					loaderPolicy := oldPolicy ]!

----- Method: MetacelloMCVersion>>executeLoadFromArray: (in category 'private') -----
executeLoadFromArray: anArray

	| loader |
	loader := MetacelloMCVersionSpecLoader on: self spec.
	loader required: anArray.
	loaderPolicy notNil ifTrue: [ loader loaderPolicy: loaderPolicy ].
	^loader load
!

----- Method: MetacelloMCVersion>>fetch (in category 'actions') -----
fetch

	^self doFetchRequiredFromArray: self spec defaultPackageNames!

----- Method: MetacelloMCVersion>>fetch: (in category 'actions') -----
fetch: required

	^required fetchRequiredForMetacelloMCVersion: self!

----- Method: MetacelloMCVersion>>fetchRequiredFromArray: (in category 'private') -----
fetchRequiredFromArray: anArray
	| originalLoader displayString newLoader |
	originalLoader := self versionSpec loader.
	newLoader := originalLoader fetchingSpecLoader.
	displayString := newLoader actionLabel , self versionNumber printString , ' of ' , self spec projectLabel.
	MetacelloPlatform current
		do: [ 
			[ 
			self versionSpec loader: newLoader.
			MetacelloPlatform current
				useStackCacheDuring: [ :dict | ^ self executeLoadFromArray: anArray ]
				defaultDictionary: Dictionary new ] ensure: [ self versionSpec loader: originalLoader ] ]
		displaying: displayString!

----- Method: MetacelloMCVersion>>ignoreImage: (in category 'accessing') -----
ignoreImage: aBool 
	"by default ignoreImage is false"
	
	self loaderPolicy ignoreImage: aBool!

----- Method: MetacelloMCVersion>>load (in category 'actions') -----
load

	^self doLoadRequiredFromArray: self spec defaultPackageNames!

----- Method: MetacelloMCVersion>>load: (in category 'actions') -----
load: required

	^required loadRequiredForMetacelloMCVersion: self!

----- Method: MetacelloMCVersion>>loadRequiredFromArray: (in category 'private') -----
loadRequiredFromArray: anArray

	| displayString |
	displayString := 'Loading ', self versionNumber printString, ' of ', self spec projectLabel.
	MetacelloPlatform current
		do: [ ^self executeLoadFromArray: anArray ]
		displaying: displayString!

----- Method: MetacelloMCVersion>>loader: (in category 'private') -----
loader: aLoader

	self versionSpec loader: aLoader!

----- Method: MetacelloMCVersion>>loaderPolicy (in category 'accessing') -----
loaderPolicy

	loaderPolicy == nil ifTrue: [ loaderPolicy := MetacelloLoaderPolicy new ].
	^ loaderPolicy!

----- Method: MetacelloMCVersion>>loaderPolicy: (in category 'accessing') -----
loaderPolicy: anObject
	loaderPolicy := anObject!

----- Method: MetacelloMCVersion>>packageAndProjectNamesToLoad:loader: (in category 'querying') -----
packageAndProjectNamesToLoad: defaultList loader: aLoader
	"Answer the list of packages and projects to be loaded: packages already loaded plust defaultList"
	
	| loadedPackageNames projectMap loadedProjectNames list |
	loadedPackageNames := ((self packages select: [:pkg | pkg isPackageLoaded: aLoader ]) 
		collect: [:pkg | pkg name ]) asSet, 
			defaultList.
	projectMap := Dictionary new.
	self  projects do: [:prj | 
		prj className ~~ nil
			ifTrue: [ | coll loaded |
				coll := projectMap at: prj className ifAbsent: [
					coll := OrderedCollection new.
					projectMap at: prj className put: coll.
					coll].
				(loaded := prj loadedPackageNames: aLoader) isEmpty 
					ifFalse: [  coll add: prj -> (loaded -> prj loadPackageList) ]]].
	loadedProjectNames := Set new.
	projectMap keysAndValuesDo: [:prjClass :coll |
		coll size <= 1
			ifTrue: [ coll do: [:assoc | loadedProjectNames add: assoc key name ]]
			ifFalse: [ 
				"multiple project references against the same configuration ... only count project as loaded
				 if there is an exact match for loaded projects...
				 See http://code.google.com/p/metacello/issues/detail?id=86"
				coll do: [:assoc | | loaded packageList |
					loaded := assoc value key. "loaded packages from project"
					packageList := assoc value value. "loadlist for project"
					(packageList difference: loaded) isEmpty
						ifTrue: [ loadedProjectNames add: assoc key name ]]]].
	list := loadedPackageNames, loadedProjectNames.
	list isEmpty ifTrue: [ ^self spec defaultPackageNames].
	^list!

----- Method: MetacelloMCVersion>>packages (in category 'querying') -----
packages
	"Answers the list of packages associated with this version"

	| packages |
	packages := OrderedCollection new.
	self spec projectDo: [:ignored | ] packageDo: [:pkg | packages add: pkg ] groupDo: [:ignored | ].
	^packages!

----- Method: MetacelloMCVersion>>packagesForSpecNamed: (in category 'querying') -----
packagesForSpecNamed: aString
	"resolves list of packages associated with the named spec.
	   If the spec is a packages, answer a list including only the package. #requires: and #includes:
			fields in the package are ignored.
	   If the spec is a project, answers an empty list.
	   If the spec is a group, answers the list of packages in the #includes: field of the group. 
			Groups in the #includes: field are expanded following the transitive closure on groups"
	"If there is no spec named <aString>, answers an empty list"

	^self packagesForSpecNamed: aString ifAbsent: [ ^#() ]!

----- Method: MetacelloMCVersion>>packagesForSpecNamed:ifAbsent: (in category 'querying') -----
packagesForSpecNamed: aString ifAbsent: aBlock
	"resolves list of packages associated with the named spec.
	   If the spec is a packages, answer a list including only the package. #requires: and #includes:
			fields in the package are ignored.
	   If the spec is a project, answers an empty list.
	   If the spec is a group, answers the list of packages in the #includes: field of the group. 
			Groups in the #includes: field are expanded following the transitive closure on groups"
	"If there is no spec named <aString>, aBlock is evaluated"

	| pkgSpec |
	pkgSpec := self spec packageNamed: aString ifAbsent: aBlock.
	^pkgSpec resolveToPackagesIn: self spec visited: MetacelloVisitedPackages new!

----- Method: MetacelloMCVersion>>record (in category 'actions') -----
record

	^self doRecordRequiredFromArray: self spec defaultPackageNames!

----- Method: MetacelloMCVersion>>record: (in category 'actions') -----
record: required

	^required recordRequiredForMetacelloMCVersion: self!

----- Method: MetacelloMCVersion>>repositoryOverrides: (in category 'accessing') -----
repositoryOverrides: repositoriesCollection 

	self loaderPolicy overrideRepositories: repositoriesCollection!

----- Method: MetacelloMCVersion>>silently: (in category 'accessing') -----
silently: aBool 
	"by default silently is false"
	
	self loaderPolicy silently: aBool!

MetacelloGenericProjectSpec subclass: #MetacelloMCProjectSpec
	instanceVariableNames: 'file'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

MetacelloMCProjectSpec subclass: #MetacelloMCBaselineOfProjectSpec
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloMCBaselineOfProjectSpec>>asBaselineProjectSpec (in category 'scripting') -----
asBaselineProjectSpec
    ^ self!

----- Method: MetacelloMCBaselineOfProjectSpec>>asProjectRegistration (in category 'scripting') -----
asProjectRegistration
    ^ MetacelloProjectRegistration fromMCBaselineProjectSpec: self!

----- Method: MetacelloMCBaselineOfProjectSpec>>canDowngradeTo: (in category 'scripting') -----
canDowngradeTo: aProjectSpec
    "cannot upgrade between baselines"

    ^ false!

----- Method: MetacelloMCBaselineOfProjectSpec>>canUpgradeTo: (in category 'scripting') -----
canUpgradeTo: aProjectSpec
  "cannot upgrade between baselines unless repositories can be upgraded"

  (self repositories canUpgradeTo: aProjectSpec repositories)
    ifTrue: [ ^ true ].
  ^ false!

----- Method: MetacelloMCBaselineOfProjectSpec>>configHasVersionString (in category 'printing') -----
configHasVersionString
  ^ false!

----- Method: MetacelloMCBaselineOfProjectSpec>>constructClassName (in category 'private') -----
constructClassName
    ^ 'BaselineOf' , self name!

----- Method: MetacelloMCBaselineOfProjectSpec>>copyForRegistration:onWrite: (in category 'mutability') -----
copyForRegistration: aMetacelloProjectRegistration onWrite: aBlock
  | copy |
  aMetacelloProjectRegistration
    baselineProjectSpecIfPresent: [ :spec | 
      copy := spec copy.
      aBlock value: copy.
      aMetacelloProjectRegistration baselineProjectSpec: copy ]
    ifAbsent: [ 
      aMetacelloProjectRegistration
        configurationProjectSpecIfPresent: [ :spec | 
          copy := spec copy.
          aBlock value: copy.
          aMetacelloProjectRegistration configurationProjectSpec: copy ]
        ifAbsent: [ aBlock value: nil ] ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>determineCurrentVersionForLoad (in category 'loading') -----
determineCurrentVersionForLoad
    ^ self version!

----- Method: MetacelloMCBaselineOfProjectSpec>>ensureConfigurationLoaded:ensured: (in category 'loading') -----
ensureConfigurationLoaded: vrsn ensured: ensured
  "answer true if the configuration should be reloaded"

  "see Issue #181 for details ... basically we always want to consider loading the baseline from a project reference, especially if the two project specs are not the same..."

  "https://github.com/dalehenrich/metacello-work/issues/181"

  ^ true!

----- Method: MetacelloMCBaselineOfProjectSpec>>ensureLoadUsing: (in category 'loading') -----
ensureLoadUsing: aLoader
  "see https://github.com/dalehenrich/metacello-work/issues/244 ... uncoditionally load
   baseline"

  [ super ensureLoadUsing: aLoader ]
    on: MetacelloIgnorePackageLoaded
    do: [ :ex | ex resume: ex packageSpec name = self name ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>hasClassName (in category 'printing') -----
hasClassName
    ^ className ~~ nil and: [ className ~= self constructClassName ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>hasConflictWithConfigurationSpec: (in category 'testing') -----
hasConflictWithConfigurationSpec: projectSpec
  "baseline can be loaded on top of a configuration without a conflict"

  ^ false!

----- Method: MetacelloMCBaselineOfProjectSpec>>hasConflictWithProjectSpec: (in category 'testing') -----
hasConflictWithProjectSpec: projectSpec
	^ projectSpec hasConflictWithBaselineSpec: self!

----- Method: MetacelloMCBaselineOfProjectSpec>>isBaselineOfProjectSpec (in category 'testing') -----
isBaselineOfProjectSpec
	^ true!

----- Method: MetacelloMCBaselineOfProjectSpec>>mergeImportLoads: (in category 'importing') -----
mergeImportLoads: aLoadList
    aLoadList
        ifNotNil: [ :otherLoads | self loads ifNil: [ loads := otherLoads ] ifNotNil: [ loads := loads , otherLoads ] ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>mergeRepositoriesSpec: (in category 'merging') -----
mergeRepositoriesSpec: anotherRepositories
  "anotherRepositories wins ... there can ever only be one repository for the 
   baseline to load from"

  "https://github.com/dalehenrich/metacello-work/issues/251"

  self repositories: anotherRepositories!

----- Method: MetacelloMCBaselineOfProjectSpec>>mergeSpec: (in category 'merging') -----
mergeSpec: anotherSpec
    ^ super mergeSpec: anotherSpec asBaselineProjectSpec!

----- Method: MetacelloMCBaselineOfProjectSpec>>projectLabel (in category 'printing') -----
projectLabel
    ^ 'baseline'!

----- Method: MetacelloMCBaselineOfProjectSpec>>repositoryBranchName (in category 'querying') -----
repositoryBranchName
  "extract a branch name from the repository ... if possible"

  "must parallel implementation of MetacelloMCBaselineProject>>setBaselineRepositoryDescription: we want the same repoSpec"

  | spec repo |
  self repositorySpecs do: [ :repoSpec | spec := repoSpec ].
  repo := spec createRepository.
  ^ repo repositoryBranchName!

----- Method: MetacelloMCBaselineOfProjectSpec>>repositoryVersionString (in category 'querying') -----
repositoryVersionString
  "extract a version string from the repository ... if possible"

  "must parallel implementation of MetacelloMCBaselineProject>>setBaselineRepositoryDescription: we want the same repoSpec"

  | spec repo |
  self repositorySpecs do: [ :repoSpec | spec := repoSpec ].
  [ repo := spec createRepository ]
    on: Error
    do: [ :ex | ^ '' ].
  ^ repo repositoryVersionString!

----- Method: MetacelloMCBaselineOfProjectSpec>>validateMergeForSpec: (in category 'merging') -----
validateMergeForSpec: aSpec
  (aSpec validateMergeWithBaselineOfSpec: self)
    ifFalse: [ 
      self
        error:
          'The project spec ' , self name printString , ' in project '
            , self project label , ' has incompatible specs. '
            , aSpec class name asString , ' and ' , self class name asString
            , ' are not compatible.' ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>validateMergeWithBaselineOfSpec: (in category 'merging') -----
validateMergeWithBaselineOfSpec: aSpec
  ^ true!

----- Method: MetacelloMCBaselineOfProjectSpec>>validateVersionString:withDefaultVersionString: (in category 'scripting') -----
validateVersionString: issues withDefaultVersionString: ignored
    self versionString
        ifNotNil: [ :vs | 
            | prj |
            prj := self project asBaselineProject.
            vs ~= prj singletonVersionName
                ifTrue: [ 
                    issues
                        add:
                            (MetacelloValidationError
                                configurationClass: self projectClass
                                reasonCode: #'invalidVersionString'
                                callSite:
                                    #'validateForScriptLoad:withDefaultVersionString:withDefaultRepositoryDecription:'
                                explanation:
                                    'version field is incorrect, should be: ' , prj singletonVersionName printString) ] ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>version (in category 'querying') -----
version
    self projectClass == nil
        ifTrue: [ ^ nil ].
    ^ self projectClassProject version!

----- Method: MetacelloMCBaselineOfProjectSpec>>version:constructor: (in category 'construction') -----
version: anObject constructor: aVersionConstructor
    self error: 'version: not allowed in a baseline project spec'!

----- Method: MetacelloMCBaselineOfProjectSpec>>versionString (in category 'querying') -----
versionString
    ^ versionString ifNil: [ self version ifNotNil: [:v | v versionString] ]!

----- Method: MetacelloMCBaselineOfProjectSpec>>versionString:constructor: (in category 'construction') -----
versionString: anObject constructor: aVersionConstructor
    self error: 'versionString: not allowed in a baseline project spec'!

MetacelloMCProjectSpec subclass: #MetacelloMCConfigurationOfProjectSpec
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloMCConfigurationOfProjectSpec>>asConfigurationProjectSpec (in category 'scripting') -----
asConfigurationProjectSpec
    ^ self!

----- Method: MetacelloMCConfigurationOfProjectSpec>>asProjectRegistration (in category 'scripting') -----
asProjectRegistration
    ^ MetacelloProjectRegistration fromMCConfigurationProjectSpec: self!

----- Method: MetacelloMCConfigurationOfProjectSpec>>constructClassName (in category 'private') -----
constructClassName
    ^ 'ConfigurationOf' , self name!

----- Method: MetacelloMCConfigurationOfProjectSpec>>copyForRegistration:onWrite: (in category 'mutability') -----
copyForRegistration: aMetacelloProjectRegistration onWrite: aBlock
  | copy |
  aMetacelloProjectRegistration
    configurationProjectSpecIfPresent: [ :spec | 
      copy := spec copy.
      aBlock value: copy.
      aMetacelloProjectRegistration configurationProjectSpec: copy ]
    ifAbsent: [ 
      aMetacelloProjectRegistration
        baselineProjectSpecIfPresent: [ :spec | 
          copy := spec copy.
          aBlock value: copy.
          aMetacelloProjectRegistration baselineProjectSpec: copy ]
        ifAbsent: [ aBlock value: nil ] ]!

----- Method: MetacelloMCConfigurationOfProjectSpec>>hasClassName (in category 'printing') -----
hasClassName
    ^ className ~~ nil and: [ className ~= self constructClassName ]!

----- Method: MetacelloMCConfigurationOfProjectSpec>>hasConflictWithBaselineSpec: (in category 'testing') -----
hasConflictWithBaselineSpec: projectSpec
	projectSpec name = self name
		ifFalse: [ ^ true ].
	projectSpec project configuration className = self project configuration className
		ifFalse: [ ^ true ].
	^ ((projectSpec repositories isEmpty or: [ self repositories isEmpty ])
		or: [ projectSpec repositories hasNoLoadConflicts: self repositories ]) not!

----- Method: MetacelloMCConfigurationOfProjectSpec>>hasConflictWithProjectSpec: (in category 'testing') -----
hasConflictWithProjectSpec: projectSpec
	^ projectSpec hasConflictWithConfigurationSpec: self!

----- Method: MetacelloMCConfigurationOfProjectSpec>>isConfigurationOfProjectSpec (in category 'testing') -----
isConfigurationOfProjectSpec
	^ true!

----- Method: MetacelloMCConfigurationOfProjectSpec>>mergeSpec: (in category 'merging') -----
mergeSpec: anotherSpec
    ^ super mergeSpec: anotherSpec asConfigurationProjectSpec!

----- Method: MetacelloMCConfigurationOfProjectSpec>>projectLabel (in category 'printing') -----
projectLabel
    ^ 'configuration'!

MetacelloMCProjectSpec subclass: #MetacelloMCNamelessProjectSpec
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloMCNamelessProjectSpec>>asProjectSpecForVersion: (in category 'scripting') -----
asProjectSpecForVersion: vrsn
  "I'm a reference spec and my project comes from the project I'm loaded from, not the project I am loading"

  "https://github.com/dalehenrich/metacello-work/issues/331"

  | proj spec |
  proj := vrsn ifNil: [ ^ self ] ifNotNil: [ vrsn versionSpec project ].
  spec := proj configurationOfProjectSpecClass for: proj.
  self copyForScriptingInto: spec.
  spec loader: self loader.
  self assert: (self className beginsWith: 'BaselineOf') not.
  ^ spec!

----- Method: MetacelloMCNamelessProjectSpec>>copyForRegistration:onWrite: (in category 'mutability') -----
copyForRegistration: aMetacelloProjectRegistration onWrite: aBlock
	self error: 'Should be converting to configuration spec for the registration, so we should not get here'!

----- Method: MetacelloMCProjectSpec class>>new (in category 'instance creation') -----
new
	self name == #MetacelloMCProjectSpec
		ifTrue: [ self error: 'This class is abstract' ].
	^ super new!

----- Method: MetacelloMCProjectSpec>>allPackagesLoaded: (in category 'testing') -----
allPackagesLoaded: aLoader
    "answer true if all of the packages (excluding projects) are loaded"

    | vrsn pkgs |
    (vrsn := self versionOrNil) == nil
        ifTrue: [ ^ false ].
    pkgs := OrderedCollection new.
    (self loadListForVersion: vrsn)
        do: [ :nm | 
            vrsn packages
                do: [ :pkg | 
                    (pkg isPackageLoaded: aLoader)
                        ifFalse: [ ^ false ] ] ].
    ^ true!

----- Method: MetacelloMCProjectSpec>>asBaselineProjectSpec (in category 'scripting') -----
asBaselineProjectSpec
    ^ self copyForScriptingInto: (MetacelloMCBaselineOfProjectSpec for: self project asBaselineProject)!

----- Method: MetacelloMCProjectSpec>>asConfigurationProjectSpec (in category 'scripting') -----
asConfigurationProjectSpec
    ^ self copyForScriptingInto: (MetacelloMCConfigurationOfProjectSpec for: self project asConfigurationProject)!

----- Method: MetacelloMCProjectSpec>>asProjectRegistration (in category 'scripting') -----
asProjectRegistration
  (self className beginsWith: 'BaselineOf')
    ifTrue: [ 
      ^ MetacelloProjectRegistration
        fromMCBaselineProjectSpec: self asBaselineProjectSpec ].
  ^ MetacelloProjectRegistration
    fromMCConfigurationProjectSpec: self asConfigurationProjectSpec!

----- Method: MetacelloMCProjectSpec>>asProjectSpec (in category 'scripting') -----
asProjectSpec
    ^ self!

----- Method: MetacelloMCProjectSpec>>asProjectSpecForVersion: (in category 'scripting') -----
asProjectSpecForVersion: vrsn
  ^ self!

----- Method: MetacelloMCProjectSpec>>baseName (in category 'accessing') -----
baseName
	^ MetacelloScriptEngine baseNameOf: self className!

----- Method: MetacelloMCProjectSpec>>canDowngradeTo: (in category 'scripting') -----
canDowngradeTo: aMetacelloProjectSpec
    ^ (super canDowngradeTo: aMetacelloProjectSpec) and: [ self file = aMetacelloProjectSpec file ]!

----- Method: MetacelloMCProjectSpec>>canUpgradeTo: (in category 'scripting') -----
canUpgradeTo: aMetacelloProjectSpec
    ^ (super canUpgradeTo: aMetacelloProjectSpec) and: [ self file = aMetacelloProjectSpec file ]!

----- Method: MetacelloMCProjectSpec>>className: (in category 'accessing') -----
className: aString
    super className: aString.
    self projectPackage: nil!

----- Method: MetacelloMCProjectSpec>>compareCurrentVersion:targetVersionStatus:using: (in category 'testing') -----
compareCurrentVersion: anOperator targetVersionStatus: targetVersionStatus using: anMCLoader
    ^ (MetacelloLookupProjectSpecForLoad new
        projectSpec: self;
        yourself) signal
        performCurrentVersionTestAgainst: self versionOrNil
        operator: anOperator
        targetVersionStatus: targetVersionStatus
        using: anMCLoader!

----- Method: MetacelloMCProjectSpec>>compareEqual: (in category 'scripting') -----
compareEqual: aMetacelloProjectSpec
    "'projectPackage repositories'"

    ^ (super compareEqual: aMetacelloProjectSpec) and: [ self file = aMetacelloProjectSpec file ]!

----- Method: MetacelloMCProjectSpec>>compareRelativeCurrentVersion:targetVersionStatus:using: (in category 'testing') -----
compareRelativeCurrentVersion: anOperator targetVersionStatus: targetVersionStatus using: anMCLoader

	| cv vrsn |
	(vrsn := self versionOrNil) == nil ifTrue: [ ^false ].
	(cv := self relativeCurrentVersion) == nil ifTrue: [ ^false ].
	(targetVersionStatus includes: cv versionStatus)
		ifTrue: [ ^cv perform: anOperator with: vrsn ].
	^false!

----- Method: MetacelloMCProjectSpec>>copyForRegistration:onWrite: (in category 'mutability') -----
copyForRegistration: aMetacelloProjectRegistration onWrite: aBlock
    self subclassResponsibility!

----- Method: MetacelloMCProjectSpec>>copyForScriptingInto: (in category 'scripting') -----
copyForScriptingInto: aProjectSpec
    ^aProjectSpec
        setName: name;
        className: className;
        versionString: versionString;
        operator: operator;
        setLoads: loads;
        preLoadDoIt: preLoadDoIt;
        postLoadDoIt: postLoadDoIt;
        repositories: repositories copy;
        file: file!

----- Method: MetacelloMCProjectSpec>>determineCurrentVersionForLoad (in category 'loading') -----
determineCurrentVersionForLoad
    "don't use self currentVersion, because we are interested in the currentVersion of the project as loaded in image, not the current version relative to our load list"

    | prjct version currentVersion cvs |
    self projectClass == nil
        ifTrue: [ ^ nil ].
    (version := self versionOrNil) == nil
        ifTrue: [ ^ nil ].
    version blessing == #'baseline'
        ifTrue: [ ^ version ].
    self loader ignoreImage
        ifTrue: [ ^ version ].
    prjct := self projectClass new project.
    prjct loader: self loader.
    (currentVersion := prjct currentVersion) == nil
        ifTrue: [ ^ nil ].
    (cvs := currentVersion versionStatus) == #'somethingLoaded'
        ifTrue: [ ^ nil ].
    (#(#'allLoadedToSpec' #'loadedToSpec' #'loadedMatchConstraints') includes: (cvs := currentVersion versionStatus))
        ifTrue: [ 
            (currentVersion perform: self operator with: version)
                ifTrue: [ 
                    "load currentVersion"
                    ^ currentVersion ].	"load version"
            ^ nil ].
    version = currentVersion
        ifTrue: [ ^ currentVersion ].	"I don't believe that it is possible to reach this point in the method, so I will be interested if I run across a case that produces this error"
    (MetacelloProjectSpecLoadConflict projectSpec: self)
        signal:
            'Project load conflict for' , prjct label printString , ' between current version ' , currentVersion printString , '('
                , cvs asString , ') and specified version ' , version printString
                , '. Press resume to continue with load anyway'.
    ^ nil
!

----- Method: MetacelloMCProjectSpec>>ensureConfigurationLoaded:ensured: (in category 'loading') -----
ensureConfigurationLoaded: vrsn ensured: ensured
  "answer true if the configuration should be reloaded:
    blessing is #development
    symbolic version (https://github.com/dalehenrich/metacello-work/issues/283)"

  (vrsn blessing == #'development' or: [ self versionString isSymbol ])
    ifTrue: [ 
      ensured ~~ #'latest'
        ifTrue: [ ^ MetacelloScriptEnsureProjectLoadedForDevelopment signal ] ].
  ^ false!

----- Method: MetacelloMCProjectSpec>>ensureLoadUsing: (in category 'loading') -----
ensureLoadUsing: aLoader
  | pp |
  pp := (MetacelloLookupProjectSpec new
    projectSpec: self;
    yourself) signal projectPackage.
  pp
    ifNil: [ 
      self
        error:
          'Unable to resolve project package for ' , self name printString
            ,
              '. It is likely that that the configuration referencing this project will not validate properly (see MetacelloToolBox class>>validateConfiguration:).' ].
  pp ensureLoadUsing: aLoader!

----- Method: MetacelloMCProjectSpec>>ensureLoadedForDevelopmentUsing: (in category 'loading') -----
ensureLoadedForDevelopmentUsing: mcLoader
  "for #development projects, always need latest version of package when contemplating a load"

  | ensured |
  ensured := mcLoader ensuredMap at: self name ifAbsent: [ nil ].
  self projectClass ~~ nil
    ifTrue: [ 
      | vrsn |
      vrsn := self versionOrNil.
      vrsn ~~ nil
        ifTrue: [ 
          (self ensureConfigurationLoaded: vrsn ensured: ensured)
            ifTrue: [ 
              mcLoader ensureForDevelopment
                ifTrue: [ 
                  | pc |
                  (pc := self projectClass) ~~ nil
                    ifTrue: [ 
                      MetacelloClearStackCacheNotification
                        signal:
                          #(#'currentVersion' #'currentVersionAgainst:' #'currentVersionInfo' #'versionConstructor' #'loadableSpecNames')
                            , {pc} ].
                  self ensureLoadUsing: mcLoader ]
                ifFalse: [ self projectPackage fetchUsing: mcLoader ].
              mcLoader ensuredMap at: self name put: #'latest' ].
          ^ self ] ].
  ensured == nil
    ifTrue: [ 
      "projectClass == nil or version == nil"
      mcLoader ensureForDevelopment
        ifTrue: [ 
          | pc |
          (pc := self projectClass) ~~ nil
            ifTrue: [ 
              MetacelloClearStackCacheNotification
                signal:
                  #(#'currentVersion' #'currentVersionAgainst:' #'currentVersionInfo' #'versionConstructor' #'loadableSpecNames')
                    , {pc} ].
          self ensureLoadUsing: mcLoader ]
        ifFalse: [ self fetchUsing: mcLoader ].
      mcLoader ensuredMap at: self name put: #'present' ]!

----- Method: MetacelloMCProjectSpec>>ensureProjectLoaded (in category 'loading') -----
ensureProjectLoaded
  "Ensure that the MetacelloProject is loaded in image. 
	 projectClass == nil or requested version non-existent warrants a project package load."

  "answer true if the projectClass exists"

  (self projectClass == nil
    or: [ 
      self versionOrNil == nil
        or: [ (loader notNil or: [ self isMutable ]) and: [ self loader ignoreImage ] ] ])
    ifTrue: [ 
      | pc |
      (pc := self projectClass) ~~ nil
        ifTrue: [ 
          MetacelloClearStackCacheNotification
            signal:
              #(#'currentVersion' #'currentVersionAgainst:' #'currentVersionInfo' #'versionConstructor' #'loadableSpecNames')
                , {pc} ].
      self projectPackage ifNil: [ ^ true ].
      self ensureLoadUsing: self loader ].
  ^ self projectClass ~~ nil!

----- Method: MetacelloMCProjectSpec>>fetchUsing: (in category 'loading') -----
fetchUsing: aLoader
    (MetacelloLookupProjectSpec new
        projectSpec: self;
        yourself) signal projectPackage fetchUsing: aLoader!

----- Method: MetacelloMCProjectSpec>>file (in category 'querying') -----
file
    file ifNil: [ ^ self className ].
    ^ file!

----- Method: MetacelloMCProjectSpec>>file: (in category 'accessing') -----
file: aString
    self shouldBeMutable.
    file := aString.
    self projectPackage: nil!

----- Method: MetacelloMCProjectSpec>>file:constructor: (in category 'construction') -----
file: aString constructor: aVersionConstructor
    aVersionConstructor fileForProject: aString!

----- Method: MetacelloMCProjectSpec>>getFile (in category 'accessing') -----
getFile
    "raw access to iv"

    ^ file!

----- Method: MetacelloMCProjectSpec>>hasConflictWithBaselineSpec: (in category 'testing') -----
hasConflictWithBaselineSpec: projectSpec
	^ self hasLoadConflicts: projectSpec!

----- Method: MetacelloMCProjectSpec>>hasConflictWithConfigurationSpec: (in category 'testing') -----
hasConflictWithConfigurationSpec: projectSpec
	^ self hasLoadConflicts: projectSpec!

----- Method: MetacelloMCProjectSpec>>hasConflictWithProjectSpec: (in category 'testing') -----
hasConflictWithProjectSpec: projectSpec
  (self className beginsWith: 'BaselineOf')
    ifTrue: [ ^ projectSpec hasConflictWithBaselineSpec: self asBaselineProjectSpec ].
  ^ projectSpec
    hasConflictWithConfigurationSpec: self asConfigurationProjectSpec!

----- Method: MetacelloMCProjectSpec>>hasNoLoadConflicts: (in category 'scripting') -----
hasNoLoadConflicts: aMetacelloProjectSpec
  "'projectPackage repositories'"

  ^ (super hasNoLoadConflicts: aMetacelloProjectSpec)
    and: [ self file = aMetacelloProjectSpec file ]!

----- Method: MetacelloMCProjectSpec>>isBaselineOfProjectSpec (in category 'testing') -----
isBaselineOfProjectSpec
	^ false!

----- Method: MetacelloMCProjectSpec>>isConfigurationOfProjectSpec (in category 'testing') -----
isConfigurationOfProjectSpec
	^ false!

----- Method: MetacelloMCProjectSpec>>isPartiallyLoaded: (in category 'testing') -----
isPartiallyLoaded: aLoader

	| vrsn |
	(vrsn := self versionOrNil) == nil ifTrue: [ ^false ].
	(self loadListForVersion: vrsn) do: [:nm |
		(vrsn packagesForSpecNamed: nm ) do: [:pkg |
			(pkg isPackageLoaded: aLoader) ifTrue: [ ^true ]]].
	^false!

----- Method: MetacelloMCProjectSpec>>isPossibleBaseline (in category 'testing') -----
isPossibleBaseline

	| vrsn |
	(vrsn := self versionOrNil) == nil ifTrue: [ ^false ].
	(vrsn allPackagesForSpecNamed: (self loadListForVersion: vrsn)) do: [:pkg |
		pkg workingCopy == nil ifTrue: [ ^false ]].
	^true!

----- Method: MetacelloMCProjectSpec>>loadPackageList (in category 'accessing') -----
loadPackageList

	| vrsn pkgs |
	(vrsn := self versionOrNil) == nil ifTrue: [ ^#() ].
	pkgs := OrderedCollection new.
	(self loadListForVersion: vrsn) do: [:nm |
		pkgs addAll: ((vrsn packagesForSpecNamed: nm ) collect: [:each | each name ])].
	^pkgs!

----- Method: MetacelloMCProjectSpec>>loadVersion: (in category 'loading') -----
loadVersion: aVersionOrNil
	"Load the correct version of the project"

	| vrsn mcLoader list |
	self ensureProjectLoaded.
	vrsn := aVersionOrNil.
	vrsn == nil
		ifTrue: [ [ vrsn := self version ]
				on: MetacelloVersionDoesNotExistError
				do: [ :ex | 
					^ (MetacelloProjectSpecLoadError projectSpec: self)
						versionDoesNotExistException: ex;
						signal:
							'No version found for ' , self versionString printString , ' of '
								, self className asString , ' because: ' , ex description ] ].
	mcLoader := self loader copy.
	mcLoader operator: self operator.
	vrsn loader: mcLoader.
	list := (mcLoader ignoreImage
		ifTrue: [ self loadListForVersion: vrsn ]
		ifFalse: [ vrsn
				packageAndProjectNamesToLoad: (self loadListForVersion: vrsn)
				loader: mcLoader ]) asSet.
	MetacelloPlatform current
		useStackCacheDuring: [ :dict | 
			| projectCache cachedList |
			projectCache := dict
				at: self projectClass
				ifAbsent: [ dict at: self projectClass put: Dictionary new ].
			(cachedList := projectCache at: vrsn ifAbsent: [  ]) == nil
				ifTrue: [ projectCache at: vrsn put: list ]
				ifFalse: [ 
					(cachedList size = list size 
					and: [ cachedList allSatisfy: [ :each | list  includes: each ] ])
						ifTrue:
							[ "no need to refetch list ... recursion stoppper (Issue 95)" ^ self ]
						ifFalse: [ projectCache at: vrsn put: list ] ].
			vrsn versionString ~= self versionString
				ifTrue: [ Transcript show: ' [' , vrsn versionString , ']' ].
			mcLoader preLoad: self.
			vrsn fetchRequiredFromArray: list.	"do the load"
			(MetacelloProjectSpecLoadedNotification new
				projectSpec: (self copy versionString: vrsn versionString)) signal.
			mcLoader postLoad: self ]
		defaultDictionary: Dictionary new!

----- Method: MetacelloMCProjectSpec>>loadedPackageNames: (in category 'accessing') -----
loadedPackageNames: aLoader

	| vrsn pkgs |
	(vrsn := self versionOrNil) == nil ifTrue: [ ^#() ].
	pkgs := OrderedCollection new.
	(self loadListForVersion: vrsn) do: [:nm |
		(vrsn packagesForSpecNamed: nm ) do: [:pkg |
			(pkg isPackageLoaded: aLoader) ifTrue: [ pkgs add: pkg name ]]].
	^pkgs!

----- Method: MetacelloMCProjectSpec>>metacelloRegistrationHash (in category 'scripting') -----
metacelloRegistrationHash
    "file"

    ^ String stringHash: self file initialHash: super metacelloRegistrationHash!

----- Method: MetacelloMCProjectSpec>>packageFileSpecFor: (in category 'accessing') -----
packageFileSpecFor: aMetacelloPackagesSpec

	^(aMetacelloPackagesSpec project projectReferenceSpec)
			name: self name;
			projectReference: self copy;
			yourself.!

----- Method: MetacelloMCProjectSpec>>projectClass (in category 'querying') -----
projectClass
    self className == nil
        ifTrue: [ ^ nil ].
    ^ Smalltalk at: self className asSymbol ifAbsent: [  ]!

----- Method: MetacelloMCProjectSpec>>projectClassProject (in category 'querying') -----
projectClassProject
    "indirection needed when projectClass is _not_ a subclass of MetacelloProject"

    ^ self projectClass new project
        setBaselineRepositoryDescription: self repositoryDescriptions;
        yourself!

----- Method: MetacelloMCProjectSpec>>projectPackage (in category 'accessing') -----
projectPackage
    projectPackage
        ifNil: [ 
            self className ifNil: [ ^ nil ].
            projectPackage := self project packageSpec.
            projectPackage name: self className.
            self getFile ifNotNil: [ projectPackage file: self file ].
            projectPackage repositories: self getRepositories ].
    ^ projectPackage!

----- Method: MetacelloMCProjectSpec>>relativeCurrentVersion (in category 'querying') -----
relativeCurrentVersion
    "currentVersion calculated relative to the loadList"

    | vrsn expanded loadList |
    (vrsn := self versionOrNil) == nil
        ifTrue: [ ^ nil ].
    expanded := [ vrsn expandToLoadableSpecNames: (loadList := self loadListForVersion: vrsn) ]
        on: Error
        do: [ :ex | 
            vrsn blessing == #'development'
                ifTrue: [ 
                    self ensureLoadUsing: self loader.
                    vrsn := self versionOrNil.
                    ex return: (vrsn expandToLoadableSpecNames: loadList) ].
            ex pass ].
    ^ self projectClassProject currentVersionAgainst: expanded!

----- Method: MetacelloMCProjectSpec>>resolveToAllPackagesIn:visited: (in category 'private') -----
resolveToAllPackagesIn: aVersionSpec visited: visited
    | vrsn |
    visited
        pushProject: [ 
            visited
                visit: self
                doing: [ :spec | 
                    spec ensureProjectLoaded.
                    vrsn := spec version.
                    ^ vrsn
                        allPackagesForSpecNamed: (self loadListForVersion: vrsn)
                        ifAbsent: [ self error: 'invalid loads: spec' ] ] ].
    ^ #()!

----- Method: MetacelloMCProjectSpec>>updateForSpawnMethod: (in category 'development support') -----
updateForSpawnMethod: sourceSpec
	"This means that this spec was used in a baseline and will be used in a version .... drop all information that isn't useful"
	
	repositories := className := operator := loads := projectPackage := nil.
	sourceSpec ~~ nil ifTrue: [ versionString := sourceSpec versionString ].!

----- Method: MetacelloMCProjectSpec>>updatePackageSpec: (in category 'development support') -----
updatePackageSpec: updatedSpecs
    "Add project copy to updatedSpecs if the current version of the project 
	 is different from the receiver's version"

    | prj currentVersion spec |
    className == nil
        ifTrue: [ ^ self ].
    prj := self projectClassProject.
    (currentVersion := prj currentVersion) = self versionOrNil
        ifTrue: [ ^ self ].
    currentVersion == nil
        ifTrue: [ ^ self ].
    spec := self copy.
    spec versionString: currentVersion versionString.
    updatedSpecs at: spec name put: spec!

----- Method: MetacelloMCProjectSpec>>validateForScriptLoad:withDefaultVersionString:withDefaultRepositoryDecription: (in category 'scripting') -----
validateForScriptLoad: aScriptEngine withDefaultVersionString: defaultVersionString withDefaultRepositoryDecription: defaultRepositoryDecription
    | issues callSite |
    issues := OrderedCollection new.
    callSite := #'validateForScriptLoad:withDefaultVersionString:withDefaultRepositoryDecription:'.
    self name
        ifNil: [ 
            issues
                add:
                    (MetacelloValidationError
                        configurationClass: self projectClass
                        reasonCode: #'incompleteProjectSpec'
                        callSite: callSite
                        explanation: 'name field required') ].
    self className
        ifNil: [ 
            issues
                add:
                    (MetacelloValidationError
                        configurationClass: self projectClass
                        reasonCode: #'incompleteProjectSpec'
                        callSite: callSite
                        explanation: 'className field required') ].
    self repositories isEmpty
        ifTrue: [ 
            defaultRepositoryDecription
                ifNotNil: [ self repository: defaultRepositoryDecription ]
                ifNil: [ 
                    issues
                        add:
                            (MetacelloValidationError
                                configurationClass: self projectClass
                                reasonCode: #'incompleteProjectSpec'
                                callSite: callSite
                                explanation: 'repository field required') ] ].
    self validateVersionString: issues withDefaultVersionString: defaultVersionString.
    ^ issues!

----- Method: MetacelloMCProjectSpec>>validateVersionString:withDefaultVersionString: (in category 'scripting') -----
validateVersionString: issues withDefaultVersionString: defaultVersionString
    self versionString
        ifNil: [ 
            defaultVersionString
                ifNotNil: [ self versionString: defaultVersionString ]
                ifNil: [ 
                    issues
                        add:
                            (MetacelloValidationError
                                configurationClass: self projectClass
                                reasonCode: #'incompleteProjectSpec'
                                callSite:
                                    #'validateForScriptLoad:withDefaultVersionString:withDefaultRepositoryDecription:'
                                explanation: 'version field required') ] ]!

----- Method: MetacelloMCProjectSpec>>version (in category 'querying') -----
version
	"Empty version string means use latestVersion or #bleedingEdge"

	self projectClass == nil
		ifTrue: [ ^ nil ].
	^ self versionString == nil
		ifTrue: [ 
			| vrsn |
			"Eventually it will become an error to not specify a project reference version as default: #stable is the preferred default"
			"self deprecated: 'Must specify a project reference version.'."
			self flag: 'deprecate after version 1.0'.
			(vrsn := self projectClassProject latestVersion) == nil
				ifTrue: [ self projectClassProject version: #bleedingEdge ]
				ifFalse: [ vrsn ] ]
		ifFalse: [ self projectClassProject version: self versionString ]!

----- Method: MetacelloMCProjectSpec>>versionForScriptEngine: (in category 'scripting') -----
versionForScriptEngine: aMetacelloScriptEngine
    | prj |
    prj := self projectClass ifNil: [ self project ] ifNotNil: [ self projectClassProject ].
    ^ ((prj projectForScriptEngine: aMetacelloScriptEngine) version: self versionString)
        silently: aMetacelloScriptEngine silently;
        ignoreImage: aMetacelloScriptEngine ignoreImage;
        cacheRepository: aMetacelloScriptEngine cacheRepository;
        repositoryOverrides: aMetacelloScriptEngine repositoryOverrides!

----- Method: MetacelloMCProjectSpec>>workingCopy (in category 'accessing') -----
workingCopy
  ^ self projectPackage workingCopy!

----- Method: Collection>>addToMetacelloRepositories: (in category '*metacello-mc') -----
addToMetacelloRepositories: aMetacelloRepositoriesSpec

	self do: [:each | each addToMetacelloRepositories: aMetacelloRepositoriesSpec ]!

----- Method: Collection>>fetchRequiredForMetacelloMCVersion: (in category '*metacello-mc') -----
fetchRequiredForMetacelloMCVersion: aMetacelloMCVersion

	^aMetacelloMCVersion doFetchRequiredFromArray: self.!

----- Method: Collection>>loadRequiredForMetacelloMCVersion: (in category '*metacello-mc') -----
loadRequiredForMetacelloMCVersion: aMetacelloMCVersion

	^aMetacelloMCVersion doLoadRequiredFromArray: self.!

----- Method: Collection>>mergeIntoMetacelloRepositories: (in category '*metacello-mc') -----
mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec

	self do: [:each | each mergeIntoMetacelloRepositories: aMetacelloRepositoriesSpec ]!

----- Method: Collection>>recordRequiredForMetacelloMCVersion: (in category '*metacello-mc') -----
recordRequiredForMetacelloMCVersion: aMetacelloMCVersion

	^aMetacelloMCVersion doRecordRequiredFromArray: self.!

----- Method: Collection>>removeFromMetacelloRepositories: (in category '*metacello-mc') -----
removeFromMetacelloRepositories: aMetacelloRepositoriesSpec

	self do: [:each | each removeFromMetacelloRepositories: aMetacelloRepositoriesSpec ]!

----- Method: Collection>>resolvePackageSpecsNamedForMetacelloMCVersion:visited:ifAbsent: (in category '*metacello-mc') -----
resolvePackageSpecsNamedForMetacelloMCVersion: aMetacelloMCVersion visited: visited ifAbsent: aBlock
    ^ aMetacelloMCVersion
        allPackagesForSpecs: (self collect: [ :ea | aMetacelloMCVersion packageNamed: ea ifAbsent: aBlock ])
        visited: visited!

----- Method: Collection>>setLoadsInMetacelloProject: (in category '*metacello-mc') -----
setLoadsInMetacelloProject: aMetacelloPackageSpec

	aMetacelloPackageSpec setLoads: self asArray.
!

MetacelloVersionValidator subclass: #MetacelloMCVersionValidator
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Validation'!

!MetacelloMCVersionValidator commentStamp: 'dkh 1/26/2012 09:49' prior: 0!
Performs configuration validation.

For programmatically decoding reason codes use:

  MetacellMCVersionValidator fullDescriptionForReasonCode: <reasonCode>

Warning reason codes:

	#notDevelopmentVersion			- the symbolic version #development refers to a non-development literal version.
	#loadWarning 						- Warning signalled during load [load validation].
	#onlyBaselineVersion 				- one or more baseline versions have been defined, but no non-baseline versions are defined.
	#stableDevelopmentVersion		- a version whose blessing is #development has been declared as a #stable version

Critical Warning reason codes:

	#duplicateVersionDefinitions 		         - there are multiple pragma methods specifying the same version
	#loadDeprecation					         - deprecation warning signalled while loading configuration [load validation]
	#missingRecommendedProjectSpecField - missing recommended fields in project reference (versionString). The versionString should be specified so that #bleedingEdge loads will be predictable and repeatable
	#noLoadableVersions 				         - no non #baseline versions defined in configuration
	#noTests 							         - no test cases defined in loaded configuration [load validation]
	#noVersionSpecified 				         - no version defined for the project reference or package. The version specified in the baseline or the latest version of the project or package in the repository will be used.
	#packageNameMismatch 			         - the name in the packageSpec does not match the name of the mcz file
	#projectClassNameFileMismatch 	         - the class name of the configuration does not match the mcz file containing the configuration
	#testDeprecation 					         - deprecation warning signalled while running configuration tests [load validation]

Error reason codes:

	#cannotResolveVersion 			- the version (project reference or symbolic version) was not found in the specified configuration
	#duplicateNames 					- multiple independent definitions for an entity with same name (project, package, or group)
	#incompleteProjectSpec 			- missing required fields in project reference (className and/or repository)
	#incorrectVersionString 			- the version declared in pragma doesn't match version in versionSpec
	#invalidDoItSelector 				- doit select must be a Symbol
	#invalidVersionString 				- versionString must be a String
	#loadError 							- error occured while loading configuration [load validation]
	#missingVersionImport 			- version specified in import pragma not defined in configuration
	#noVersionsDefined 				- no usable baseline or version defined in configuration ... configuration cannot be loaded
	#projectCreationError 				- error occured while resolving project reference
	#shadowedNames 					- name duplication between packages and projects
	#testFailures						- test failures while running tests [load validation]
	#versionCompositionError 			- error while creating versionSpec from pragmas


!

----- Method: MetacelloMCVersionValidator class>>populateReasonCodeDescriptions (in category 'private') -----
populateReasonCodeDescriptions
    "update MetacelloMCVersionValidator class comment to include any changes to descriptions"

    | dict |
    dict := super populateReasonCodeDescriptions.
    dict
        at: #'notDevelopmentVersion'
            put: 'the symbolic version #development refers to a non-development literal version.';
        at: #'loadWarning' put: 'Warning signalled during load [load validation].';
        at: #'stableDevelopmentVersion'
            put: 'a version whose blessing is #development has been declared as a #stable version.'.	"Warnings"
    dict
        at: #'loadDeprecation' put: 'deprecation warning signalled while loading configuration [load validation].';
        at: #'missingRecommendedProjectSpecField'
            put:
                'missing recommended fields in project reference (versionString). The versionString should be specified so that #bleedingEdge loads will be predictable and repeatable.';
        at: #'noLoadableVersions' put: 'no non #baseline versions defined in configuration.';
        at: #'noTests' put: 'no test cases defined in loaded configuration [load validation].';
        at: #'noVersionSpecified'
            put:
                'no version defined for the project reference or package. The version specified in the baseline or the latest version of the project or package in the repository will be used.';
        at: #'testDeprecation'
            put: 'deprecation warning signalled while running configuration tests [load validation].'.	"Critical Warnings"
    dict
        at: #'loadError' put: 'error occured while loading configuration [load validation].';
        at: #'testFailures' put: 'test failures while running tests [load validation].'.	"Errors"
    ^ dict!

----- Method: MetacelloMCVersionValidator class>>validateConfigurationLoad: (in category 'instance creation') -----
validateConfigurationLoad: configurationClass
	^ ((self new)
		configurationClass: configurationClass;
		yourself) validateProjectLoad!

----- Method: MetacelloMCVersionValidator class>>validateConfigurationLoad:version: (in category 'instance creation') -----
validateConfigurationLoad: configurationClass version: versionString
	^self validateConfigurationLoad: configurationClass version: versionString loads: #()!

----- Method: MetacelloMCVersionValidator class>>validateConfigurationLoad:version:loads: (in category 'instance creation') -----
validateConfigurationLoad: configurationClass version: versionString loads: loadList
	^ ((self new)
		configurationClass: configurationClass;
		yourself) validateProjectVersionLoad: versionString loads: loadList!

----- Method: MetacelloMCVersionValidator>>criticalWarningReasonCodes (in category 'private') -----
criticalWarningReasonCodes
	^ super criticalWarningReasonCodes
		, #(#noLoadableVersions #noTests #testDeprecation #loadDeprecation #noVersionSpecified #'missingRecommendedProjectSpecField' )!

----- Method: MetacelloMCVersionValidator>>errorReasonCodes (in category 'private') -----
errorReasonCodes
	^ super errorReasonCodes, #(#loadError #testFailures )!

----- Method: MetacelloMCVersionValidator>>validateBaselineVersionSpec: (in category 'validation') -----
validateBaselineVersionSpec: versionSpec
    | projectNames packageNames groupNames versionMessage |
    self
        validateDoIts: versionSpec
        versionString: versionSpec versionString
        errorMessage: ' version ' , versionSpec versionString printString.
    projectNames := Set new.
    packageNames := Set new.
    groupNames := Set new.
    versionMessage := ' in version ' , versionSpec versionString printString.
    versionSpec
        projectDo: [ :projectSpec | 
            projectSpec resolveProjectSpec className == nil
                ifTrue: [ 
                    self
                        recordValidationError:
                            'Missing required field (className:) for project reference ' , projectSpec name printString , ' in version '
                                , versionSpec versionString printString
                        versionString: versionSpec versionString
                        callSite: #'validateBaselineVersionSpec:'
                        reasonCode: #'incompleteProjectSpec' ].
            projectSpec resolveProjectSpec versionString == nil
                ifTrue: [ 
                    self
                        recordValidationCriticalWarning:
                            'Missing recommended field (versionString:) for project reference ' , projectSpec name printString , ' in version '
                                , versionSpec versionString printString
                        versionString: versionSpec versionString
                        callSite: #'validateBaselineVersionSpec:'
                        reasonCode: #'missingRecommendedProjectSpecField' ].
            projectSpec hasRepository
                ifTrue: [ 
                    (self recurse and: [ projectSpec versionString ~~ nil ])
                        ifTrue: [ 
                            | project |
                            projectSpec resolveProjectSpec ensureProjectLoaded.
                            project := self
                                validateProjectCreationFrom: projectSpec resolveProjectSpec projectClass
                                onError: [ :ex | 
                                    self
                                        recordValidationError: 'Error creating project reference: ' , ex description
                                        versionString: versionSpec versionString
                                        callSite: #'validateBaselineVersionSpec:'
                                        reasonCode: #'projectCreationError'.
                                    nil ].
                            project ~~ nil
                                ifTrue: [ 
                                    self validationReport
                                        addAll:
                                            (self class
                                                validateProject: project
                                                version: projectSpec versionString
                                                debug: self debug
                                                recurse: self recurse
                                                visited: self visited) ] ] ]
                ifFalse: [ 
                    self
                        recordValidationError:
                            'Missing required field (repository:) for project reference ' , projectSpec name printString , ' in version '
                                , versionSpec versionString printString
                        versionString: versionSpec versionString
                        callSite: #'validateBaselineVersionSpec:'
                        reasonCode: #'incompleteProjectSpec' ].
            self
                validateDoIts: projectSpec
                versionString: versionSpec versionString
                errorMessage: projectSpec name printString , versionMessage.
            (projectNames includes: projectSpec name)
                ifTrue: [ 
                    self
                        recordValidationError:
                            'Duplicate projects named' , projectSpec name printString , versionMessage
                        versionString: versionSpec versionString
                        callSite: #'validateBaselineVersionSpec:'
                        reasonCode: #'duplicateNames' ]
                ifFalse: [ projectNames add: projectSpec name ] ]
        packageDo: [ :packageSpec | 
            self
                validateDoIts: packageSpec
                versionString: versionSpec versionString
                errorMessage: packageSpec name printString , versionMessage.
            (packageNames includes: packageSpec name)
                ifTrue: [ 
                    self
                        recordValidationError:
                            'Duplicate packages named' , packageSpec name printString , versionMessage
                        versionString: versionSpec versionString
                        callSite: #'validateBaselineVersionSpec:'
                        reasonCode: #'duplicateNames' ]
                ifFalse: [ projectNames add: packageSpec name ] ]
        groupDo: [ :groupSpec | 
            (groupNames includes: groupSpec name)
                ifTrue: [ 
                    self
                        recordValidationError: 'Duplicate groups named' , groupSpec name printString , versionMessage
                        versionString: versionSpec versionString
                        callSite: #'validateBaselineVersionSpec:'
                        reasonCode: #'duplicateNames' ]
                ifFalse: [ projectNames add: groupSpec name ] ].
    (packageNames intersection: projectNames) notEmpty
        ifTrue: [ 
            self
                recordValidationError: 'Names duplicated between packages and projects' , versionMessage
                versionString: versionSpec versionString
                callSite: #'validateBaselineVersionSpec:'
                reasonCode: #'shadowedNames' ].
    (groupNames intersection: projectNames) notEmpty
        ifTrue: [ 
            self
                recordValidationError: 'Names duplicated between groups and projects' , versionMessage
                versionString: versionSpec versionString
                callSite: #'validateBaselineVersionSpec:'
                reasonCode: #'shadowedNames' ].
    (projectNames intersection: packageNames) notEmpty
        ifTrue: [ 
            self
                recordValidationError: 'Names duplicated between projects and packages' , versionMessage
                versionString: versionSpec versionString
                callSite: #'validateBaselineVersionSpec:'
                reasonCode: #'shadowedNames' ].
    (groupNames intersection: packageNames) notEmpty
        ifTrue: [ 
            self
                recordValidationError: 'Names duplicated between groups and packages' , versionMessage
                versionString: versionSpec versionString
                callSite: #'validateBaselineVersionSpec:'
                reasonCode: #'shadowedNames' ].
    (projectNames intersection: groupNames) notEmpty
        ifTrue: [ 
            self
                recordValidationError: 'Names duplicated between projects and groups' , versionMessage
                versionString: versionSpec versionString
                callSite: #'validateBaselineVersionSpec:'
                reasonCode: #'shadowedNames' ].
    (packageNames intersection: groupNames) notEmpty
        ifTrue: [ 
            self
                recordValidationError: 'Names duplicated between packages and groups' , versionMessage
                versionString: versionSpec versionString
                callSite: #'validateBaselineVersionSpec:'
                reasonCode: #'shadowedNames' ]!

----- Method: MetacelloMCVersionValidator>>validateCleanLoadAndTestsForVersion:loads: (in category 'loading') -----
validateCleanLoadAndTestsForVersion: version loads: loadList
	| cleanLoad cleanTests |
	cleanTests := cleanLoad := false.
	[ 
	self validateVersionLoad: version loads: loadList.
	cleanLoad := true ]
		on: Error , Warning
		do: [ :ex | 
			(ex isKindOf: Error)
				ifTrue: [ 
					self
						recordValidationError:
							'Error while loading version ' , version versionString printString , ' in ' , self configurationClass name asString
								, ' ' , ex description
						versionString: version versionString
						callSite: #validateCleanLoadAndTestsForVersion:loads:
						reasonCode: #loadError ].
			(ex isKindOf: Warning)
				ifTrue: [ 
					(ex isKindOf: Deprecation)
						ifTrue: [ 
							self
								recordValidationCriticalWarning:
									'Deprecation while loading version ' , version versionString printString , ' in '
										, self configurationClass name asString , ' ' , ex description
								versionString: version versionString
								callSite: #validateCleanLoadAndTestsForVersion:loads:
								reasonCode: #loadDeprecation ]
						ifFalse: [ 
							self
								recordValidationWarning:
									'Warning while loading version ' , version versionString printString , ' in ' , self configurationClass name asString
										, ' ' , ex description
								versionString: version versionString
								callSite: #validateCleanLoadAndTestsForVersion:loads:
								reasonCode: #loadWarning.
							Smalltalk
								at: #UndeclaredVariableWarning
								ifPresent: [ :undeclaredWrning | 
									(ex isKindOf: undeclaredWrning)
										ifTrue: [ ex resume: true ] ].
							ex resume ] ] ].
	cleanLoad
		ifTrue: [ 
			cleanTests := [ self validateVersionTests: version ]
				on: Deprecation
				do: [ :ex | 
					| message |
					message := 'Deprecation warning while running tests for version ' , version versionString printString , ' in '
						, self configurationClass name asString , ' ' , ex description.	"Deprecation warning for release tests is the same as a test failure"
					self
						recordValidationCriticalWarning: message
						versionString: version versionString
						callSite: #validateCleanLoadAndTestsForVersion:loads:
						reasonCode: #testDeprecation.
					ex return: false ].
			cleanTests
				ifTrue: [ MetacelloCleanLoadAndTestsNotification signal: version ]
				ifFalse: [ MetacelloCleanLoadNotification signal: version ] ]!

----- Method: MetacelloMCVersionValidator>>validateProjectLoad (in category 'loading') -----
validateProjectLoad
	| issues project versions currentVersion collectedIssues |
	(issues := self validateProject select: [ :issue | issue isError ]) notEmpty
		ifTrue: [ ^ issues ].
	project := self configurationClass project.
	collectedIssues := issues.
	versions := project versions
		select: [ :version | 
			validationReport := nil.
			version blessing ~~ #broken
				and: [ 
					version blessing ~~ #baseline
						and: [ (issues := (self validateProject: project version: version versionString) select: [ :issue | issue isCritical ]) isEmpty ] ] ].
	validationReport := collectedIssues.
	versions isEmpty
		ifTrue: [ 
			self
				recordValidationCriticalWarning: 'No non #baseline versions  available  in ' , self configurationClass name asString
				callSite: #validateProjectLoad
				reasonCode: #noLoadableVersions.
			^ self validationReport ].
	(currentVersion := project currentVersion) ~~ nil
		ifTrue: [ 
			| index |
			index := versions indexOf: currentVersion.
			versions := versions copyFrom: index to: versions size ].
	versions do: [ :version | self validateCleanLoadAndTestsForVersion: version loads: #('ALL') ].
	^ self validationReport!

----- Method: MetacelloMCVersionValidator>>validateProjectVersionLoad:loads: (in category 'loading') -----
validateProjectVersionLoad: versionString loads: loadList
	| issues project version |
	(issues := (self validateProjectVersion: versionString) select: [ :issue | issue isError ]) notEmpty
		ifTrue: [ ^ issues ].
	project := self configurationClass project.
	version := project
		version: versionString
		ifAbsent: [ 
			self
				recordValidationError: 'Version ' , versionString printString , ' does not exist.'
				callSite: #validateProjectVersionLoad:loads:
				reasonCode: #cannotResolveVersion.
			^ self validationReport ].
	version blessing = #broken
		ifTrue: [ self error: 'The specified version is #broken' ].
	self validateCleanLoadAndTestsForVersion: version loads: loadList.
	^ self validationReport
!

----- Method: MetacelloMCVersionValidator>>validateVersionLoad:loads: (in category 'loading') -----
validateVersionLoad: version loads: loadList
	| list |
	list := loadList asOrderedCollection.
	list isEmpty
		ifTrue: [ list add: 'default' ].
	(version groups includes: 'Tests')
		ifTrue: [ list add: 'Tests' ].
	version load: list!

----- Method: MetacelloMCVersionValidator>>validateVersionSpec: (in category 'private') -----
validateVersionSpec: versionSpec
  versionSpec blessing value == #'broken'
    ifTrue: [ ^ self ].
  versionSpec
    projectDo: [ :projectSpec | 
      | referencedProjectSpec |
      projectSpec versionString == nil
        ifTrue: [ 
          self
            recordValidationCriticalWarning:
              'No version specified for the project reference ' , projectSpec name printString
                , ' in version ' , versionSpec versionString printString
            versionString: versionSpec versionString
            callSite: #'validateVersionSpec:'
            reasonCode: #'noVersionSpecified' ].
      referencedProjectSpec := projectSpec referencedSpec.
      versionSpec blessing value == #'baseline'
        ifTrue: [ 
          referencedProjectSpec hasRepository
            ifTrue: [ 
              (referencedProjectSpec file beginsWith: referencedProjectSpec className)
                ifFalse: [ 
                  self
                    recordValidationCriticalWarning:
                      'The class name of project ' , referencedProjectSpec className printString
                        , ' does not match the file name '
                        , referencedProjectSpec file printString
                        , ' in version ' , versionSpec versionString printString
                    versionString: versionSpec versionString
                    callSite: #'validateVersionSpec:'
                    reasonCode: #'projectClassNameFileMismatch' ] ]
            ifFalse: [ 
              self
                recordValidationError:
                  'The specification for the project reference ' , projectSpec name printString
                    , ' in version ' , versionSpec versionString printString
                    , ' is missing the required repository field'
                versionString: versionSpec versionString
                callSite: #'validateVersionSpec:'
                reasonCode: #'incompleteProjectSpec' ] ].
      referencedProjectSpec ensureProjectLoaded
        ifTrue: [ 
          [ projectSpec version ]
            on: MetacelloVersionDoesNotExistError
            do: [ :ex | 
              | explanation |
              explanation := projectSpec versionString == nil
                ifTrue: [ 'the default version' ]
                ifFalse: [ 'version ' , projectSpec versionString printString ].
              self
                recordValidationError:
                  'Cannot resolve ' , explanation , ' for the project reference '
                    , projectSpec name printString , ' in version '
                    , versionSpec versionString printString
                versionString: versionSpec versionString
                callSite: #'validateVersionSpec:'
                reasonCode: #'cannotResolveVersion' ] ] ]
    packageDo: [ :packageSpec | 
      (packageSpec file beginsWith: packageSpec name)
        ifFalse: [ 
          self
            recordValidationCriticalWarning:
              'The name of package ' , packageSpec name printString
                , ' does not match the file name '
                , packageSpec file printString , ' in version '
                , versionSpec versionString printString
            versionString: versionSpec versionString
            callSite: #'validateVersionSpec:'
            reasonCode: #'packageNameMismatch' ].
      packageSpec file = packageSpec name
        ifTrue: [ 
          self
            recordValidationCriticalWarning:
              'No version specified for the package ' , packageSpec name printString
                , ' in version ' , versionSpec versionString printString
            versionString: versionSpec versionString
            callSite: #'validateVersionSpec:'
            reasonCode: #'noVersionSpecified' ] ]
    groupDo: [ :ignored |  ].
  self validateBaselineVersionSpec: versionSpec!

----- Method: MetacelloMCVersionValidator>>validateVersionSpecForSymbolicVersion:symbolicVersion: (in category 'private') -----
validateVersionSpecForSymbolicVersion: versionSpec symbolicVersion: symbolicVersionString
	| blessing |
	versionSpec blessing value == #broken
		ifTrue: [ ^ self ].
	blessing := versionSpec blessing value.
	(symbolicVersionString == #development and: [ blessing ~~ #development ])
		ifTrue: [ 
			self
				recordValidationWarning:
					'Symbolic version ' , symbolicVersionString printString , ' refers to a version' , versionSpec versionString printString
						, ' whose blessing ' , blessing printString , ' is not #development'
				versionString: versionSpec versionString
				callSite: #validateVersionSpecForSymbolicVersion:symbolicVersion:
				reasonCode: #notDevelopmentVersion ]!

----- Method: MetacelloMCVersionValidator>>validateVersionTests: (in category 'loading') -----
validateVersionTests: version
	| testCases cleanTests |
	testCases := IdentitySet new.
	cleanTests := true.
	version currentlyLoadedClassesInVersion
		do: [ :class | 
			((class inheritsFrom: TestCase) and: [ class isAbstract not ])
				ifTrue: [ testCases add: class ] ].
	testCases
		do: [ :testCase | 
			| testResults |
			testResults := testCase suite run.
			testResults defects notEmpty
				ifTrue: [ 
					self
						recordValidationError:
							'Test failures in tests ' , testCase name asString , ' for ' , version versionString printString , ' in '
								, self configurationClass name asString , ' ' , testResults printString
						versionString: version versionString
						callSite: #validateVersionTests:
						reasonCode: #testFailures.
					cleanTests := false ] ].
	testCases isEmpty
		ifTrue: [ 
			self
				recordValidationCriticalWarning:
					'No test cases for ' , version versionString printString , ' in ' , self configurationClass name asString
				versionString: version versionString
				callSite: #validateVersionTests:
				reasonCode: #noTests.
			cleanTests := false ].
	^ cleanTests!

----- Method: MetacelloMCVersionValidator>>warningReasonCodes (in category 'private') -----
warningReasonCodes
	^ super warningReasonCodes, #(#loadWarning #notDevelopmentVersion #stableDevelopmentVersion)!

Object subclass: #MetacelloConfigTemplate
	instanceVariableNames: 'project'
	classVariableNames: 'LastVersionLoad'
	poolDictionaries: ''
	category: 'Metacello-MC-Model'!

!MetacelloConfigTemplate commentStamp: '<historical>' prior: 0!
Copy me to create a new configuration or edit and evaluate the following doits.

        "Create configuration class and initial baseline method"

        MetacelloToolBox 
                createBaseline: '1.0-baseline'
                for: 'MyProject'
                repository: 'http://www.example.com/MyProjectRepository'
                requiredProjects: #('Gofer')
                packages: #('MyProject-Core' 'MyProject-Tests')
                dependencies:
                        {('MyProject-Core' -> #('Gofer')).
                         ('MyProject-Tests' -> #('MyProject-Core'))}
                groups:
                        {('default' -> #('Core')).
                        ('Core' -> #('MyProject-Core')).
                        ('Tests' -> #('MyProject-Tests'))}.

	   "create initial development method from the baseline"

         MetacelloToolBox
               createDevelopment: '1.0'
               for: 'MyProject'
                importFromBaseline: '1.0-baseline'
                description: 'initial version'.
!

----- Method: MetacelloConfigTemplate class>>DevelopmentSupport (in category 'development support') -----
DevelopmentSupport

"See the methods in the 'development support' category on the class-side of MetacelloBaseConfiguration. Decide what development support methods you would like to use and copy them the the class-side of your configuration."
	<apiDocumentation>!

----- Method: MetacelloConfigTemplate class>>baseConfigurationClassIfAbsent: (in category 'private') -----
baseConfigurationClassIfAbsent: aBlock

	^Smalltalk
		at: #'ConfigurationOf'
		ifAbsent: [ 
			self ensureMetacelloBaseConfiguration.
			Smalltalk at: #'ConfigurationOf' ifAbsent: aBlock ].!

----- Method: MetacelloConfigTemplate class>>ensureMetacello (in category 'private') -----
ensureMetacello

	(self baseConfigurationClassIfAbsent: []) ensureMetacello!

----- Method: MetacelloConfigTemplate class>>ensureMetacelloBaseConfiguration (in category 'private') -----
ensureMetacelloBaseConfiguration
  Smalltalk
    at: #'ConfigurationOf'
    ifAbsent: [ 
      | repository version |
      repository := MCHttpRepository
        location: 'http://smalltalkhub.com/mc/dkh/metacello/main'
        user: ''
        password: ''.
      repository
        versionReaderForFileNamed: 'Metacello-Base-dkh.107'
        do: [ :reader | 
          version := reader version.
          version load.
          version workingCopy repositoryGroup addRepository: repository ] ]!

----- Method: MetacelloConfigTemplate class>>isMetacelloConfig (in category 'metacello tool support') -----
isMetacelloConfig
	"Answer true and the Metacello tools will operate on you"
	
	^true!

----- Method: MetacelloConfigTemplate class>>load (in category 'loading') -----
load
	"Load the #stable version defined for this platform. The #stable version is the version that is recommended to be used on this platform."

	"self load"

	<apiDocumentation>
	^(self project version: #stable) load!

----- Method: MetacelloConfigTemplate class>>loadBleedingEdge (in category 'loading') -----
loadBleedingEdge
	"Load the latest versions of the mcz files defined for this project. It is not likely that the #bleedingEdge has been tested."

	"self loadBleedingEdge"

	<apiDocumentation>
	^(self project version: #bleedingEdge) load!

----- Method: MetacelloConfigTemplate class>>loadDevelopment (in category 'loading') -----
loadDevelopment
	"Load the #development version defined for this platform. The #development version will change over time and is not expected to be stable."

	"self loadDevelopment"

	<apiDocumentation>
	^(self project version: #development) load!

----- Method: MetacelloConfigTemplate class>>project (in category 'accessing') -----
project

	^self new project!

----- Method: MetacelloConfigTemplate class>>validate (in category 'development support') -----
validate
	"Check the configuration for Errors, Critical Warnings, and Warnings (see class comment for MetacelloMCVersionValidator for more information). 
	Errors identify specification issues that will result in unexpected behaviour when you load the configuration. 
	Critical Warnings identify specification issues that may result in unexpected behavior when you load the configuration.
	Warnings identify specification issues that are technically correct, but are worth take a look at."

	"self validate"

	<apiDocumentation>
	self ensureMetacello.
	^ ((Smalltalk at: #MetacelloToolBox) validateConfiguration: self debug: #() recurse: false) explore!

----- Method: MetacelloConfigTemplate>>customProjectAttributes (in category 'accessing') -----
customProjectAttributes
    "Edit to return a collection of any custom attributes e.g. for conditional loading: Array with: #'Condition1' with: #'Condition2.
	For more information see: http://code.google.com/p/metacello/wiki/CustomProjectAttrributes "

    ^ #()!

----- Method: MetacelloConfigTemplate>>project (in category 'accessing') -----
project
    ^ project
        ifNil: [ 
            "Bootstrap Metacello if it is not already loaded"
            self class ensureMetacello.
            project := MetacelloMCProject new projectAttributes: self customProjectAttributes.	"Create the Metacello project"
            (Smalltalk at: #'MetacelloVersionConstructor') on: self project: project.	"Construct the project"
            project loadType: #'linear'.	"change to #atomic if desired"
            project ]!

Object subclass: #MetacelloConfigTemplateExample
	instanceVariableNames: 'project'
	classVariableNames: 'LastVersionLoad'
	poolDictionaries: ''
	category: 'Metacello-MC-Model'!

!MetacelloConfigTemplateExample commentStamp: '<historical>' prior: 0!
Copy me to create a new configuration or edit and evaluate the following doits.

        "Create configuration class and initial baseline method"

        MetacelloToolBox 
                createBaseline: '1.0-baseline'
                for: 'MyProject'
                repository: 'http://www.example.com/MyProjectRepository'
                requiredProjects: #('Gofer')
                packages: #('MyProject-Core' 'MyProject-Tests')
                dependencies:
                        {('MyProject-Core' -> #('Gofer')).
                         ('MyProject-Tests' -> #('MyProject-Core'))}
                groups:
                        {('default' -> #('Core')).
                        ('Core' -> #('MyProject-Core')).
                        ('Tests' -> #('MyProject-Tests'))}.

	   "create initial development method from the baseline"

         MetacelloToolBox
               createDevelopment: '1.0'
               for: 'MyProject'
                importFromBaseline: '1.0-baseline'
                description: 'initial version'.
!

----- Method: MetacelloConfigTemplateExample class>>DevelopmentSupport (in category 'development support') -----
DevelopmentSupport

"See the methods in the 'development support' category on the class-side of MetacelloBaseConfiguration. Decide what development support methods you would like to use and copy them the the class-side of your configuration."
	<apiDocumentation>!

----- Method: MetacelloConfigTemplateExample class>>baseConfigurationClassIfAbsent: (in category 'private') -----
baseConfigurationClassIfAbsent: aBlock

	^Smalltalk
		at: #MetacelloBaseConfiguration
		ifAbsent: [ 
			self ensureMetacelloBaseConfiguration.
			Smalltalk at: #MetacelloBaseConfiguration ifAbsent: aBlock ].!

----- Method: MetacelloConfigTemplateExample class>>ensureMetacello (in category 'private') -----
ensureMetacello

	(self baseConfigurationClassIfAbsent: []) ensureMetacello!

----- Method: MetacelloConfigTemplateExample class>>ensureMetacelloBaseConfiguration (in category 'private') -----
ensureMetacelloBaseConfiguration

	Smalltalk
		at: #MetacelloBaseConfiguration
		ifAbsent: [ 
			| repository version |
			repository := MCHttpRepository location: 'http://seaside.gemstone.com/ss/metacello' user: '' password: ''.
			repository
				versionReaderForFileNamed: 'Metacello-Base-DaleHenrichs.2.mcz'
				do: [ :reader | 
					version := reader version.
					version load.
					version workingCopy repositoryGroup addRepository: repository ] ]!

----- Method: MetacelloConfigTemplateExample class>>isMetacelloConfig (in category 'metacello tool support') -----
isMetacelloConfig
	"Answer true and the Metacello tools will operate on you"
	
	^true!

----- Method: MetacelloConfigTemplateExample class>>load (in category 'loading') -----
load
	"Load the #stable version defined for this platform. The #stable version is the version that is recommended to be used on this platform."

	"self load"

	<apiDocumentation>
	^(self project version: #stable) load!

----- Method: MetacelloConfigTemplateExample class>>loadBleedingEdge (in category 'loading') -----
loadBleedingEdge
	"Load the latest versions of the mcz files defined for this project. It is not likely that the #bleedingEdge has been tested."

	"self loadBleedingEdge"

	<apiDocumentation>
	^(self project version: #bleedingEdge) load!

----- Method: MetacelloConfigTemplateExample class>>loadDevelopment (in category 'loading') -----
loadDevelopment
	"Load the #development version defined for this platform. The #development version will change over time and is not expected to be stable."

	"self loadDevelopment"

	<apiDocumentation>
	^(self project version: #development) load!

----- Method: MetacelloConfigTemplateExample class>>project (in category 'accessing') -----
project

	^self new project!

----- Method: MetacelloConfigTemplateExample class>>validate (in category 'development support') -----
validate
	"Check the configuration for Errors, Critical Warnings, and Warnings (see class comment for MetacelloMCVersionValidator for more information). 
	Errors identify specification issues that will result in unexpected behaviour when you load the configuration. 
	Critical Warnings identify specification issues that may result in unexpected behavior when you load the configuration.
	Warnings identify specification issues that are technically correct, but are worth take a look at."

	"self validate"

	<apiDocumentation>
	self ensureMetacello.
	^ ((Smalltalk at: #MetacelloToolBox) validateConfiguration: self debug: #() recurse: false) explore!

----- Method: MetacelloConfigTemplateExample>>baseline10: (in category 'baselines') -----
baseline10: spec
	"Baselines are used by convention in Metacello and essentially are nothing else than normal versions.
	Name the baseline after the first version it was introduced.
	In this case 1.0-baseline was introduced the first time with the 1.0 version defined in the #version10 method.
	Metacello only uses the following tag to figure out the name of this baseline:"
	<version: '1.0-baseline'>

	"Using #common makes this dependency declaration available for all Smalltalks.
	If you need more fine-grained control you can add several #for:do: sections for other releases."
	spec for: #common do: [	
		spec blessing: #baseline.
		"specify the default repository for your project's packages"
		spec repository: 'http://smalltalkhub.com/mc/JohnDoe/MyProject/main'.
	
		"use separate methods for external projects"
		self 
			fuelMetalevel: spec;
			fileSystemLegacy: spec.
		
		"specify the dependencies between packages and projects"
		spec
			"a package without dependencies:"
			package: 'MyProject-Core';
			package: 'MyProject-Tests' with: [ 
				"Specfiy dependencies using the #requires: directive, you can refer to any name here, in this case to an external project"
				spec requires: #('MyProject-Core' 'FuelMetalevel' 'FileSystemLegacy')].
			
		"using groups certain packages and projects can be loaded conditionally"
		spec 
			"load the tests by default"
			group: 'default' with: #('core' 'test');
			group: 'test'    with: #('MyProject-Tests');
			group: 'core'    with: #('MyProject-Core')]!

----- Method: MetacelloConfigTemplateExample>>customProjectAttributes (in category 'accessing') -----
customProjectAttributes
	 "Edit to return a collection of any custom attributes e.g. for conditional loading: Array with: #'Condition1' with: #'Condition2.
	For more information see: http://code.google.com/p/metacello/wiki/CustomProjectAttrributes"

	^ #().!

----- Method: MetacelloConfigTemplateExample>>development: (in category 'tags') -----
development: spec
	"By convention the development branch should point to a fixed version that is regularly updated and might contain unstable code.
	The name used by Metacello is only defined by the following pragma:"
	<symbolicVersion: #development >
	
	"For the development tag refer to a fixed version which you update if you commit new code.
	Note that you can refer here to any other version name from this configuration"
	spec for: #'common' version: 'dev'.!

----- Method: MetacelloConfigTemplateExample>>fileSystemLegacy: (in category 'external projects') -----
fileSystemLegacy: spec
	"This is an example of an external project which does not have a configuration yet.
	Note that the package name is only used in the Metacello configuration and does not have be exactly the same as the Monticello project/version name."
	spec package: 'FileSystemLegacy' with: [
		spec 
			repository: 'http://smalltalkhub.com/mc/PharoExtras/FileSystemLegacy/main';
			"if you do not specify a version, automatically the newest version is chose."
			file:  'FileSystem-Legacy-JohanBrichau.2' ]!

----- Method: MetacelloConfigTemplateExample>>fuelMetalevel: (in category 'external projects') -----
fuelMetalevel: spec

	"Specify a dependency on an external project which has it's own configuration.
	The given project name can be chosen freely, for simplicity use the same name as the configuration or the conditional group you load."
	spec project: 'FuelMetalevel' with: [
		spec 
			repository: 'http://ss3.gemstone.com/ss/Fuel';
			className: 'ConfigurationOfFuel';
			"if you want to load by default a special group usse the #loads: message plus a group name of the external configuration"
			loads: #FuelMetalevel ].!

----- Method: MetacelloConfigTemplateExample>>project (in category 'accessing') -----
project

	^ project ifNil: [ 
		"Bootstrap Metacello if it is not already loaded"
		(self class baseConfigurationClassIfAbsent: []) ensureMetacello.
		"Construct Metacello project"
		project := MetacelloMCProject new projectAttributes: self customProjectAttributes. 
		(Smalltalk at: #MetacelloVersionConstructor) on: self project: project.
		project loadType: #linear. "change to #atomic if desired"
		project ]!

----- Method: MetacelloConfigTemplateExample>>stable: (in category 'tags') -----
stable: spec
	"Symbolic versions can be used to introduce an indirection to a version number.
	The real name used by Metacello is only defined by the following pragma:"
	<symbolicVersion: #stable >
	
	"If another version is stable for a differen Smalltalk use a specific name"
	"spec for: #'pharo1.4.x' version: '0.9'"
	
	"Specfiy which exact version you want to load"
	spec for: #'common' version: '1.0'.!

----- Method: MetacelloConfigTemplateExample>>version10: (in category 'versions') -----
version10: spec
	"The name for this version is solely defined by the following pragma:"
	<version: '1.0' imports: #('1.0-baseline') >
	"Baselines are used to define more complex setups for your project.
	If you want to use external projects and have fine-graind control of the dependencies between packages use the #imports: part.
	See the #baseline10: for more details."
	
	"Using #for:do: with the #common release specifier the following version declaration is valid for all platforms."
	spec for: #common do: [
		spec 
			description: 'Version 1.0 the current stable release';
			blessing: #release;
			author: 'John Doe';
			timestamp: '2013-05-01'.
		
		"Specify the versions for each package and external project defined in the baseline, here the 1.0-baseline defined in the baseline10 method."
		spec
			"For standard Monticello packages simply refere to the full version name without the extension:"
			package: 'MyProject-Core'  with: 'MyProject-Core-JohnDoe.52';
			package: 'MyProject-Tests' with: 'MyProject-Tests-JohnDoe.73';
			
			"External projects versions are specified using #project:with:.
			Note the project name referes to the name used in the Metacello declaration.
			FuelMetalevel is defined in the #fuelMetalevel: method."
			project: 'FuelMetalevel' with: #stable ].
		
	"If you want to specify different version on other platforms add another #for:do: block with a different version identifier."!

----- Method: MetacelloConfigTemplateExample>>versionDevelopment: (in category 'versions') -----
versionDevelopment: spec
	"version specification for the current development branch, see #version10 for a complete explanation of a version declaration.
	In this case the 'dev' version uses the same baselin as version '1.0':"
	<version: 'dev' imports: #('1.0-baseline') >
	
	"Update this configuration regulrarly with intermediate releases.
	If a version is more stable or should stay accessible copy this 'dev' definition and give it a proper version name on its own.
	For example, in this case you might want to split a new version '1.1' by copying over this definition."
	spec for: #common do: [
		spec 
			description: 'Development Version';
			blessing: #development;
			author: 'John Doe';
			timestamp: '2013-05-09'.
		
		spec
			package: 'MyProject-Core'  with: 'MyProject-Core-JohnDoe.152';
			package: 'MyProject-Tests' with: 'MyProject-Tests-JohnDoe.173';
			"note that for the 'dev' version we rely on the #development version of the external FuleMetalevel project"
			project: 'FuelMetalevel'   with: #development ].!

Object subclass: #MetacelloDirective
	instanceVariableNames: 'spec loader'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloDirective class>>loadPackage:externalReference:loader: (in category 'instance creation') -----
loadPackage: aPackageSpec externalReference: externalReference loader: aLoader

	^MetacelloPackageLoadDirective new
		spec: aPackageSpec externalReference: externalReference  loader: aLoader!

----- Method: MetacelloDirective class>>loader: (in category 'instance creation') -----
loader: aLoader

	^self new
		loader: aLoader!

----- Method: MetacelloDirective class>>postLoadSpec:loader: (in category 'instance creation') -----
postLoadSpec: packageOrVersionSpec loader: aLoader

	^MetacelloPostLoadDirective new
		spec: packageOrVersionSpec loader: aLoader!

----- Method: MetacelloDirective class>>preLoadSpec:loader: (in category 'instance creation') -----
preLoadSpec: packageOrVersionSpec loader: aLoader

	^MetacelloPreLoadDirective new
		spec: packageOrVersionSpec loader: aLoader!

----- Method: MetacelloDirective>>addTo: (in category 'actions') -----
addTo: aLoaderDirective

	aLoaderDirective add: self!

----- Method: MetacelloDirective>>directivesDo: (in category 'enumerating') -----
directivesDo: aBlock

	aBlock value: self!

----- Method: MetacelloDirective>>label (in category 'printing') -----
label

	^self spec label!

----- Method: MetacelloDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	self subclassResponsibility!

----- Method: MetacelloDirective>>loader (in category 'accessing') -----
loader

	^loader!

----- Method: MetacelloDirective>>loader: (in category 'accessing') -----
loader: aLoader

	loader := aLoader!

----- Method: MetacelloDirective>>packageDirectivesDo: (in category 'enumerating') -----
packageDirectivesDo: aBlock!

----- Method: MetacelloDirective>>packageDo: (in category 'actions') -----
packageDo: aBlock!

----- Method: MetacelloDirective>>postLoadDo: (in category 'actions') -----
postLoadDo: aBlock!

----- Method: MetacelloDirective>>preLoadDo: (in category 'actions') -----
preLoadDo: aBlock!

----- Method: MetacelloDirective>>prepostLoadDirectivesDo: (in category 'enumerating') -----
prepostLoadDirectivesDo: aBlock!

----- Method: MetacelloDirective>>prepostLoadDo: (in category 'enumerating') -----
prepostLoadDo: aBlock!

----- Method: MetacelloDirective>>printOn: (in category 'printing') -----
printOn: aStream

	self printOn: aStream indent: 0!

----- Method: MetacelloDirective>>printOn:indent: (in category 'printing') -----
printOn: aStream indent: indent

	indent timesRepeat: [ aStream tab ].
	aStream
		nextPutAll: self title;
		nextPutAll: ' : ';
		nextPutAll: self label.!

----- Method: MetacelloDirective>>printString (in category 'printing') -----
printString
	"Explicit override of superclass implementation. When you are printing a loadDirective it is annoying to have it truncated."

	^String streamContents: [:s | self printOn: s]!

----- Method: MetacelloDirective>>spec (in category 'accessing') -----
spec

	^spec!

----- Method: MetacelloDirective>>spec:loader: (in category 'initialize-release') -----
spec: packageOrVersionSpec loader: aLoader

	spec := packageOrVersionSpec.
	loader := aLoader!

----- Method: MetacelloDirective>>title (in category 'accessing') -----
title

	self subclassResponsibility!

----- Method: MetacelloDirective>>versionDirectivesDepthFirstDo: (in category 'enumerating') -----
versionDirectivesDepthFirstDo: aBlock!

----- Method: MetacelloDirective>>versionDirectivesDo: (in category 'enumerating') -----
versionDirectivesDo: aBlock!

----- Method: MetacelloDirective>>versionDo: (in category 'actions') -----
versionDo: aBlock!

MetacelloDirective subclass: #MetacelloPackageLoadDirective
	instanceVariableNames: 'resolvedReference externalReference'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloPackageLoadDirective>>externalReference (in category 'accessing') -----
externalReference
	^ externalReference!

----- Method: MetacelloPackageLoadDirective>>file (in category 'accessing') -----
file

	^self externalReference name!

----- Method: MetacelloPackageLoadDirective>>label (in category 'printing') -----
label

	^self file!

----- Method: MetacelloPackageLoadDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	aLoaderDirective loadPackageDirective: self gofer: aGofer!

----- Method: MetacelloPackageLoadDirective>>packageDirectivesDo: (in category 'enumerating') -----
packageDirectivesDo: aBlock

	aBlock value: self!

----- Method: MetacelloPackageLoadDirective>>packageDo: (in category 'enumerating') -----
packageDo: aBlock

	aBlock value: self!

----- Method: MetacelloPackageLoadDirective>>packageName (in category 'accessing') -----
packageName

	^self externalReference packageName!

----- Method: MetacelloPackageLoadDirective>>repository (in category 'accessing') -----
repository

	^self externalReference repository!

----- Method: MetacelloPackageLoadDirective>>resolvedReference (in category 'accessing') -----
resolvedReference
	^ resolvedReference!

----- Method: MetacelloPackageLoadDirective>>resolvedReference: (in category 'accessing') -----
resolvedReference: anObject
	resolvedReference := anObject!

----- Method: MetacelloPackageLoadDirective>>spec:externalReference:loader: (in category 'initialize-release') -----
spec: aPackageSpec externalReference: anExternalReference loader: aLoader

	super spec: aPackageSpec loader: aLoader.
	externalReference := anExternalReference!

----- Method: MetacelloPackageLoadDirective>>title (in category 'accessing') -----
title

	^'load'!

MetacelloDirective subclass: #MetacelloPrePostLoadDirective
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

MetacelloPrePostLoadDirective subclass: #MetacelloPostLoadDirective
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloPostLoadDirective>>addTo: (in category 'actions') -----
addTo: aLoaderDirective

	spec postLoadDoIt value ~~ nil ifTrue: [ aLoaderDirective add: self ]!

----- Method: MetacelloPostLoadDirective>>label (in category 'printing') -----
label

	^super label, ' >> ', self spec postLoadDoIt value asString!

----- Method: MetacelloPostLoadDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	aLoaderDirective loadPostloadDirective: self.!

----- Method: MetacelloPostLoadDirective>>postLoadDo: (in category 'actions') -----
postLoadDo: aBlock

	aBlock value: self!

----- Method: MetacelloPostLoadDirective>>title (in category 'accessing') -----
title

	^'postload'!

MetacelloPrePostLoadDirective subclass: #MetacelloPreLoadDirective
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloPreLoadDirective>>addTo: (in category 'actions') -----
addTo: aLoaderDirective

	spec preLoadDoIt value ~~ nil ifTrue: [ aLoaderDirective add: self ]!

----- Method: MetacelloPreLoadDirective>>label (in category 'printing') -----
label

	^super label, ' >> ', self spec preLoadDoIt value asString!

----- Method: MetacelloPreLoadDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	aLoaderDirective loadPreloadDirective: self.!

----- Method: MetacelloPreLoadDirective>>preLoadDo: (in category 'actions') -----
preLoadDo: aBlock

	aBlock value: self!

----- Method: MetacelloPreLoadDirective>>title (in category 'accessing') -----
title

	^'preload'!

----- Method: MetacelloPrePostLoadDirective>>evaluateSupplyingAnswers: (in category 'actions') -----
evaluateSupplyingAnswers: loadBlock

	| answers |
	(answers := self spec answers) notEmpty
		ifTrue: [ loadBlock valueSupplyingMetacelloAnswers: answers ]
		ifFalse: [ loadBlock value]!

----- Method: MetacelloPrePostLoadDirective>>prepostLoadDirectivesDo: (in category 'enumerating') -----
prepostLoadDirectivesDo: aBlock

	aBlock value: self!

----- Method: MetacelloPrePostLoadDirective>>prepostLoadDo: (in category 'enumerating') -----
prepostLoadDo: aBlock

	aBlock value: self!

MetacelloDirective subclass: #MetacelloVersionLoadDirective
	instanceVariableNames: 'loadDirectives'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

MetacelloVersionLoadDirective subclass: #MetacelloAtomicLoadDirective
	instanceVariableNames: 'packageloads preloads postloads'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloAtomicLoadDirective>>directivesDo: (in category 'enumerating') -----
directivesDo: aBlock

	aBlock value: self.
	self preloads do: [:directive | directive directivesDo: aBlock ].
	self loadDirectives do: [:directive | directive directivesDo: aBlock ].
	self postloads do: [:directive | directive directivesDo: aBlock ].!

----- Method: MetacelloAtomicLoadDirective>>finalizeLoad: (in category 'actions') -----
finalizeLoad: aGofer
	"load the accumulated packages (if any), reset the package list"

	| pkgLoads |
	self preloads do: [:directive | super loadPreloadDirective: directive ].
	preloads := nil.
	(pkgLoads := self packageloads) notEmpty 
		ifTrue: [
			self loader loadingSpecLoader 
				loadPackageDirectives: pkgLoads 
				gofer: aGofer.
			self packageloads: nil ].
	self postloads do: [:directive | super loadPostloadDirective: directive ].
	postloads := nil!

----- Method: MetacelloAtomicLoadDirective>>loadAtomicLoadDirective:gofer: (in category 'actions') -----
loadAtomicLoadDirective: aLoaderDirective gofer: aGofer

	aLoaderDirective loadDirectives do: [:directive | directive loadUsing: self gofer: aGofer ].!

----- Method: MetacelloAtomicLoadDirective>>loadLinearLoadDirective:gofer: (in category 'actions') -----
loadLinearLoadDirective: aLoaderDirective gofer: aGofer

	self finalizeLoad: aGofer.
	super loadLinearLoadDirective: aLoaderDirective gofer: aGofer!

----- Method: MetacelloAtomicLoadDirective>>loadPackageDirective:gofer: (in category 'loading') -----
loadPackageDirective: aPackageLoadDirective gofer: aGofer
	"accumulate packages"
	
	self packageloads add: aPackageLoadDirective!

----- Method: MetacelloAtomicLoadDirective>>loadPostloadDirective: (in category 'loading') -----
loadPostloadDirective: aPostloadDirective
	"accumulate postloads"

	self postloads add: aPostloadDirective!

----- Method: MetacelloAtomicLoadDirective>>loadPreloadDirective: (in category 'loading') -----
loadPreloadDirective: aPreloadDirective 
	"accumulate preloads"

	self preloads add: aPreloadDirective!

----- Method: MetacelloAtomicLoadDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	self loadDirectives isEmpty ifTrue: [ ^self ].
	aLoaderDirective loadAtomicLoadDirective: self gofer: aGofer.!

----- Method: MetacelloAtomicLoadDirective>>packageloads (in category 'accessing') -----
packageloads

	packageloads == nil ifTrue: [ packageloads := OrderedCollection new ].
	^ packageloads!

----- Method: MetacelloAtomicLoadDirective>>packageloads: (in category 'accessing') -----
packageloads: anObject
	packageloads := anObject!

----- Method: MetacelloAtomicLoadDirective>>postloads (in category 'accessing') -----
postloads

	postloads == nil ifTrue: [ postloads := OrderedCollection new ].
	^ postloads!

----- Method: MetacelloAtomicLoadDirective>>preloads (in category 'accessing') -----
preloads

	preloads == nil ifTrue: [ preloads := OrderedCollection new ].
	^ preloads!

----- Method: MetacelloAtomicLoadDirective>>prepostLoadDirectivesDo: (in category 'enumerating') -----
prepostLoadDirectivesDo: aBlock

	self preloads do: [:directive | directive prepostLoadDirectivesDo: aBlock ].
	self loadDirectives do: [:directive | directive prepostLoadDirectivesDo: aBlock ].
	self postloads do: [:directive | directive prepostLoadDirectivesDo: aBlock ].!

----- Method: MetacelloAtomicLoadDirective>>prepostLoadsDo: (in category 'enumerating') -----
prepostLoadsDo: aBlock

	self preloads do: [:directive | directive prepostLoadDo: aBlock ].
	self loadDirectives do: [:directive | directive prepostLoadDo: aBlock ].
	self postloads do: [:directive | directive prepostLoadDo: aBlock ].!

----- Method: MetacelloAtomicLoadDirective>>title (in category 'accessing') -----
title

	^'atomic load'!

MetacelloVersionLoadDirective subclass: #MetacelloExplicitLoadDirective
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloExplicitLoadDirective>>explicitLoadUsing:gofer: (in category 'actions') -----
explicitLoadUsing: aLoaderDirective gofer: aGofer

	aLoaderDirective loadLinearLoadDirective: self gofer: aGofer.!

----- Method: MetacelloExplicitLoadDirective>>explicitLoadWithPolicy: (in category 'actions') -----
explicitLoadWithPolicy: aLoadPolicy

	| gofer |
	gofer := MetacelloGofer new.
	gofer disablePackageCache.
	gofer repository: aLoadPolicy cacheRepository.
	self explicitLoadUsing: self gofer: gofer!

----- Method: MetacelloExplicitLoadDirective>>isExplicit (in category 'testing') -----
isExplicit

	^true!

----- Method: MetacelloExplicitLoadDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	aLoaderDirective loadExplicitLoadDirective: self gofer: aGofer.!

----- Method: MetacelloExplicitLoadDirective>>title (in category 'accessing') -----
title

	^'explicit load'!

MetacelloVersionLoadDirective subclass: #MetacelloLinearLoadDirective
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Directives'!

----- Method: MetacelloLinearLoadDirective>>loadUsing:gofer: (in category 'actions') -----
loadUsing: aLoaderDirective gofer: aGofer

	self loadDirectives isEmpty ifTrue: [ ^self ].
	aLoaderDirective loadLinearLoadDirective: self gofer: aGofer.!

----- Method: MetacelloLinearLoadDirective>>title (in category 'accessing') -----
title

	^'linear load'!

----- Method: MetacelloVersionLoadDirective>>add: (in category 'actions') -----
add: aDirective

	self loadDirectives add: aDirective!

----- Method: MetacelloVersionLoadDirective>>directivesDo: (in category 'enumerating') -----
directivesDo: aBlock

	aBlock value: self.
	self loadDirectives do: [:directive | directive directivesDo: aBlock ].!

----- Method: MetacelloVersionLoadDirective>>finalizeLoad: (in category 'actions') -----
finalizeLoad: aGofer
	"nothing special for linear loads"!

----- Method: MetacelloVersionLoadDirective>>isExplicit (in category 'testing') -----
isExplicit

	^false!

----- Method: MetacelloVersionLoadDirective>>label (in category 'printing') -----
label

	self spec == nil ifTrue: [ ^'' ].
	^self spec label!

----- Method: MetacelloVersionLoadDirective>>loadAtomicLoadDirective:gofer: (in category 'actions') -----
loadAtomicLoadDirective: aLoaderDirective gofer: aGofer

	aLoaderDirective loadDirectives do: [:directive | directive loadUsing: aLoaderDirective gofer: aGofer ].
	aLoaderDirective finalizeLoad: aGofer.!

----- Method: MetacelloVersionLoadDirective>>loadDirectives (in category 'accessing') -----
loadDirectives

	loadDirectives == nil ifTrue: [ loadDirectives := OrderedCollection new ].
	^ loadDirectives!

----- Method: MetacelloVersionLoadDirective>>loadDirectives: (in category 'accessing') -----
loadDirectives: anObject
	loadDirectives := anObject!

----- Method: MetacelloVersionLoadDirective>>loadExplicitLoadDirective:gofer: (in category 'actions') -----
loadExplicitLoadDirective: aLoaderDirective gofer: aGofer
	"load has already been performed, no need to load again"!

----- Method: MetacelloVersionLoadDirective>>loadLinearLoadDirective:gofer: (in category 'actions') -----
loadLinearLoadDirective: aLoaderDirective gofer: aGofer

	aLoaderDirective loadDirectives do: [:directive | directive loadUsing: aLoaderDirective gofer: aGofer ].
	aLoaderDirective finalizeLoad: aGofer.!

----- Method: MetacelloVersionLoadDirective>>loadPackageDirective:gofer: (in category 'loading') -----
loadPackageDirective: aPackageLoadDirective gofer: aGofer

	aPackageLoadDirective loader loadingSpecLoader 
		loadPackageDirective: aPackageLoadDirective 
		gofer: aGofer!

----- Method: MetacelloVersionLoadDirective>>loadPostloadDirective: (in category 'loading') -----
loadPostloadDirective: aPostloadDirective 

	| block |
	(block :=  aPostloadDirective spec postLoadDoItBlock) ~~ nil
		ifTrue: [
			aPostloadDirective evaluateSupplyingAnswers: [ block valueWithPossibleArgs: 
					(Array 
						with: aPostloadDirective loader 
						with: aPostloadDirective spec) ].
			Transcript cr; show: 'Evaluated -> ', aPostloadDirective spec label, ' >> ', aPostloadDirective spec postLoadDoIt value asString]!

----- Method: MetacelloVersionLoadDirective>>loadPreloadDirective: (in category 'loading') -----
loadPreloadDirective: aPreloadDirective 

	| block |
	(block :=  aPreloadDirective spec preLoadDoItBlock) ~~ nil
		ifTrue: [
			aPreloadDirective evaluateSupplyingAnswers: [ block valueWithPossibleArgs: 
					(Array 
						with: aPreloadDirective loader 
						with: aPreloadDirective spec) ].
			Transcript cr; show: 'Evaluated -> ', aPreloadDirective spec label, ' >> ', aPreloadDirective spec preLoadDoIt value asString]!

----- Method: MetacelloVersionLoadDirective>>loadWithPolicy: (in category 'actions') -----
loadWithPolicy: aLoadPolicy

	| gofer |
	gofer := MetacelloGofer new.
	gofer disablePackageCache.
	gofer repository: aLoadPolicy cacheRepository.
	self loadUsing: self gofer: gofer!

----- Method: MetacelloVersionLoadDirective>>packageDirectivesDo: (in category 'enumerating') -----
packageDirectivesDo: aBlock

	self loadDirectives do: [:directive | directive packageDirectivesDo: aBlock ].!

----- Method: MetacelloVersionLoadDirective>>packagesDo: (in category 'enumerating') -----
packagesDo: aBlock

	self loadDirectives do: [:directive | directive packageDo: aBlock ].!

----- Method: MetacelloVersionLoadDirective>>prepostLoadDirectivesDo: (in category 'enumerating') -----
prepostLoadDirectivesDo: aBlock

	self loadDirectives do: [:directive | directive prepostLoadDirectivesDo: aBlock ].!

----- Method: MetacelloVersionLoadDirective>>prepostLoadsDo: (in category 'enumerating') -----
prepostLoadsDo: aBlock

	self loadDirectives do: [:directive | directive prepostLoadDo: aBlock ].!

----- Method: MetacelloVersionLoadDirective>>printLoadDirectivesOn:indent: (in category 'printing') -----
printLoadDirectivesOn: aStream indent: indent

	self loadDirectives do: [:each |
		aStream cr. 
		each printOn: aStream indent: indent + 1 ].!

----- Method: MetacelloVersionLoadDirective>>printOn:indent: (in category 'printing') -----
printOn: aStream indent: indent

	super printOn: aStream indent: indent.
	self printLoadDirectivesOn: aStream indent: indent!

----- Method: MetacelloVersionLoadDirective>>spec (in category 'accessing') -----
spec
	"Expected to be a MetacelloVersionSpec"
	
	(spec == nil  and: [  self loader ~~ nil ]) 
		ifTrue: [ 
			^[ self loader spec versionSpec ] 
				on: MessageNotUnderstood
				do: [:ex | ex return: self loader spec ]].
	^spec!

----- Method: MetacelloVersionLoadDirective>>versionDirectivesDepthFirstDo: (in category 'enumerating') -----
versionDirectivesDepthFirstDo: aBlock

	self loadDirectives do: [:directive | directive versionDirectivesDepthFirstDo: aBlock ].
	aBlock value: self.!

----- Method: MetacelloVersionLoadDirective>>versionDirectivesDo: (in category 'enumerating') -----
versionDirectivesDo: aBlock

	aBlock value: self.
	self loadDirectives do: [:directive | directive versionDirectivesDo: aBlock ].!

----- Method: MetacelloVersionLoadDirective>>versionDo: (in category 'enumerating') -----
versionDo: aBlock

	aBlock value: self.!

----- Method: MetacelloVersionLoadDirective>>versionsDo: (in category 'enumerating') -----
versionsDo: aBlock

	self loadDirectives do: [:directive | directive versionDo: aBlock ].!

Object subclass: #MetacelloLoadData
	instanceVariableNames: 'dataMap versionInfoMap packageNameMap'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloLoadData>>addVersion:versionInfo:resolvedReference:packageSpec: (in category 'accessing') -----
addVersion: version versionInfo: versionInfo resolvedReference: resolvedReference packageSpec: packageSpec
	| vis |
	"check for duplicates and use the one that is being added"
	(vis := self packageNameMap at: packageSpec name ifAbsent: [  ]) ~~ nil
		ifTrue: [ 
			"remove old references"
			vis
				do: [ :vi | 
					self dataMap removeKey: vi name.
					self versionInfoMap removeKey: vi name ] ].
	self dataMap
		at: version info name
		put:
			{version.
			resolvedReference.
			packageSpec}.
	self versionInfoMap at: versionInfo name put: {versionInfo}.
	self packageNameMap at: packageSpec name put: {versionInfo}!

----- Method: MetacelloLoadData>>ancestorsFor:ifAbsent: (in category 'versionInfo') -----
ancestorsFor: packageSpec ifAbsent: aBlock

	^self versionInfoMap 
		at: packageSpec file 
		ifAbsent: [ 
			self  packageNameMap 
				at: packageSpec name
				ifAbsent: aBlock ]!

----- Method: MetacelloLoadData>>currentVersionInfoFor:ifAbsent: (in category 'versionInfo') -----
currentVersionInfoFor: packageSpec ifAbsent: aBlock

	^self versionInfoMap 
		at: packageSpec file 
		ifPresent: [ :v | v first ]
		ifAbsent: [ 
			self  packageNameMap 
				at: packageSpec name
				ifPresent: [ :v | v first ]
				ifAbsent: aBlock ]!

----- Method: MetacelloLoadData>>dataMap (in category 'accessing') -----
dataMap

	dataMap == nil ifTrue: [ dataMap := Dictionary new ].
	^dataMap!

----- Method: MetacelloLoadData>>do: (in category 'enumerating') -----
do: aBlock

	self dataMap valuesDo: [:ar |
		aBlock value: (ar at: 1) value: (ar at: 2) value: (ar at: 3) ]!

----- Method: MetacelloLoadData>>isEmpty (in category 'testing') -----
isEmpty

	^self dataMap isEmpty!

----- Method: MetacelloLoadData>>packageNameMap (in category 'accessing') -----
packageNameMap

	packageNameMap == nil ifTrue: [ packageNameMap := Dictionary new ].
	^packageNameMap!

----- Method: MetacelloLoadData>>versionInfoMap (in category 'accessing') -----
versionInfoMap

	versionInfoMap == nil ifTrue: [ versionInfoMap := Dictionary new ].
	^versionInfoMap!

Object subclass: #MetacelloLoaderPolicy
	instanceVariableNames: 'overrideRepositories repositoryMap ensuredMap cacheRepository cacheGofer ignoreImage loadData loadDirective silently'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloLoaderPolicy class>>overrideRepositories: (in category 'instance creation') -----
overrideRepositories: aCollection

	^self new overrideRepositories: aCollection!

----- Method: MetacelloLoaderPolicy>>cacheGofer (in category 'accessing') -----
cacheGofer

	cacheGofer == nil 
		ifTrue: [ 
			"don't use a caching Gofer here, since we expect the contents to change during a fetch operation"
			cacheGofer := Gofer new. 
			cacheGofer disablePackageCache.
			cacheGofer repository: self cacheRepository. ].
	^ cacheGofer!

----- Method: MetacelloLoaderPolicy>>cacheRepository (in category 'accessing') -----
cacheRepository

	cacheRepository == nil ifTrue: [ cacheRepository := MCDictionaryRepository new ].
	^ cacheRepository!

----- Method: MetacelloLoaderPolicy>>cacheRepository: (in category 'accessing') -----
cacheRepository: anMCRepository

	cacheRepository := anMCRepository.
	"getting a new repository, so wipe out the cacheGofer and ensureMap"
	ensuredMap := cacheGofer := nil!

----- Method: MetacelloLoaderPolicy>>ensuredMap (in category 'accessing') -----
ensuredMap

	ensuredMap == nil ifTrue: [ ensuredMap := Dictionary new ].
	^ensuredMap!

----- Method: MetacelloLoaderPolicy>>ensuredMap: (in category 'accessing') -----
ensuredMap: anObject
	ensuredMap := anObject!

----- Method: MetacelloLoaderPolicy>>hasRepositoryOverrides (in category 'testing') -----
hasRepositoryOverrides

	^self overrideRepositories ~~ nil!

----- Method: MetacelloLoaderPolicy>>ignoreImage (in category 'accessing') -----
ignoreImage
	^ ignoreImage!

----- Method: MetacelloLoaderPolicy>>ignoreImage: (in category 'accessing') -----
ignoreImage: anObject
	ignoreImage := anObject!

----- Method: MetacelloLoaderPolicy>>initialize (in category 'initialize-release') -----
initialize

	self 
		repositoryMap; 
		cacheRepository;
		ensuredMap.
	ignoreImage := false!

----- Method: MetacelloLoaderPolicy>>load (in category 'actions') -----
load

	overrideRepositories := Array with: self cacheRepository. "ensure that hasRepositoryOverrides is true"
	self loadDirective loadWithPolicy: self!

----- Method: MetacelloLoaderPolicy>>loadData (in category 'accessing') -----
loadData

 	loadData == nil ifTrue: [ loadData := MetacelloLoadData new ].
	^loadData!

----- Method: MetacelloLoaderPolicy>>loadDirective (in category 'accessing') -----
loadDirective

	loadDirective == nil ifTrue: [ loadDirective := MetacelloLinearLoadDirective new ].
	^ loadDirective!

----- Method: MetacelloLoaderPolicy>>overrideRepositories (in category 'accessing') -----
overrideRepositories
	^ overrideRepositories!

----- Method: MetacelloLoaderPolicy>>overrideRepositories: (in category 'accessing') -----
overrideRepositories: anObject
	overrideRepositories := anObject!

----- Method: MetacelloLoaderPolicy>>pushAtomicLoadDirectivesDuring:for: (in category 'actions') -----
pushAtomicLoadDirectivesDuring: aBlock for: aLoader

	self pushLoadDirective: (MetacelloAtomicLoadDirective loader: aLoader) during: aBlock.!

----- Method: MetacelloLoaderPolicy>>pushExplicitLoadDirectivesDuring:for: (in category 'actions') -----
pushExplicitLoadDirectivesDuring: aBlock for: aLoader

	| directive |
	directive := MetacelloExplicitLoadDirective loader: aLoader.
	self pushLoadDirective: directive during: aBlock.
	^directive!

----- Method: MetacelloLoaderPolicy>>pushLinearLoadDirectivesDuring:for: (in category 'actions') -----
pushLinearLoadDirectivesDuring: aBlock for: aLoader

	self pushLoadDirective: (MetacelloLinearLoadDirective loader: aLoader) during: aBlock.!

----- Method: MetacelloLoaderPolicy>>pushLoadDirective:during: (in category 'private') -----
pushLoadDirective: aLoaderDirective during: aBlock

	|  oldRoot |
	self loadDirective add: aLoaderDirective.
	oldRoot := loadDirective.
	loadDirective := aLoaderDirective.
	aBlock ensure: [ loadDirective := oldRoot ].!

----- Method: MetacelloLoaderPolicy>>repositoryMap (in category 'accessing') -----
repositoryMap

	repositoryMap == nil ifTrue: [ repositoryMap := Dictionary new ].
	^repositoryMap!

----- Method: MetacelloLoaderPolicy>>repositoryMap: (in category 'accessing') -----
repositoryMap: anObject
	repositoryMap := anObject!

----- Method: MetacelloLoaderPolicy>>resetCacheGofer (in category 'accessing') -----
resetCacheGofer

	cacheGofer := nil!

----- Method: MetacelloLoaderPolicy>>silently (in category 'accessing') -----
silently

	silently == nil ifTrue: [ silently := false ].
	^ silently!

----- Method: MetacelloLoaderPolicy>>silently: (in category 'accessing') -----
silently: anObject
	silently := anObject!

Object subclass: #MetacelloMCPartiallyLoadedStatus
	instanceVariableNames: 'hasNoPackage hasNoProject aProjectIsLoaded aPackageIsLoaded aLoadedProjectIsExact aLoadedPackageIsExact aLoadedProjectIsCurrent aLoadedPackageIsCurrent aLoadedProjectIsNotCurrent aLoadedPackageIsNotCurrent aProjectNotLoaded aPackageNotLoaded vrsnStatus abort'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloMCPartiallyLoadedStatus class>>new (in category 'instance creation') -----
new
	^ self basicNew initialize!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedPackageIsCurrent (in category 'accessing') -----
aLoadedPackageIsCurrent
	^ aLoadedPackageIsCurrent!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedPackageIsCurrent: (in category 'accessing') -----
aLoadedPackageIsCurrent: aBoolean
	aLoadedPackageIsCurrent := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedPackageIsExact (in category 'accessing') -----
aLoadedPackageIsExact
	^ aLoadedPackageIsExact!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedPackageIsExact: (in category 'accessing') -----
aLoadedPackageIsExact: aBoolean
	aLoadedPackageIsExact := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedPackageIsNotCurrent (in category 'accessing') -----
aLoadedPackageIsNotCurrent
	^ aLoadedPackageIsNotCurrent!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedPackageIsNotCurrent: (in category 'accessing') -----
aLoadedPackageIsNotCurrent: aBoolean
	aLoadedPackageIsNotCurrent := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedProjectIsCurrent: (in category 'accessing') -----
aLoadedProjectIsCurrent: aBoolean
	aLoadedProjectIsCurrent := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedProjectIsExact (in category 'accessing') -----
aLoadedProjectIsExact
	^ aLoadedProjectIsExact!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedProjectIsExact: (in category 'accessing') -----
aLoadedProjectIsExact: aBoolean
	aLoadedProjectIsExact := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedProjectIsNotCurrent (in category 'accessing') -----
aLoadedProjectIsNotCurrent
	^ aLoadedProjectIsNotCurrent!

----- Method: MetacelloMCPartiallyLoadedStatus>>aLoadedProjectIsNotCurrent: (in category 'accessing') -----
aLoadedProjectIsNotCurrent: aBoolean
	aLoadedProjectIsNotCurrent := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aPackageIsLoaded (in category 'accessing') -----
aPackageIsLoaded
	^aPackageIsLoaded!

----- Method: MetacelloMCPartiallyLoadedStatus>>aPackageIsLoaded: (in category 'accessing') -----
aPackageIsLoaded: aBoolean
	aPackageIsLoaded := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aPackageNotLoaded (in category 'accessing') -----
aPackageNotLoaded
	^aPackageNotLoaded!

----- Method: MetacelloMCPartiallyLoadedStatus>>aPackageNotLoaded: (in category 'accessing') -----
aPackageNotLoaded: aBoolean
	aPackageNotLoaded := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aProjectIsLoaded (in category 'accessing') -----
aProjectIsLoaded
	^aProjectIsLoaded!

----- Method: MetacelloMCPartiallyLoadedStatus>>aProjectIsLoaded: (in category 'accessing') -----
aProjectIsLoaded: aBoolean
	aProjectIsLoaded := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>aProjectNotLoaded (in category 'accessing') -----
aProjectNotLoaded
	^aProjectNotLoaded!

----- Method: MetacelloMCPartiallyLoadedStatus>>aProjectNotLoaded: (in category 'accessing') -----
aProjectNotLoaded: aBoolean
	aProjectNotLoaded := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>abort (in category 'accessing') -----
abort
	^ abort!

----- Method: MetacelloMCPartiallyLoadedStatus>>abort: (in category 'accessing') -----
abort: aBoolean
	abort := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>evaluateStatus: (in category 'evaulation') -----
evaluateStatus: validStatusList
	^self abort
		ifTrue: [ false ]
		ifFalse: [ 
			(self hasNoProject or: [ self vrsnStatus isEmpty ])
				ifTrue: [ true ]
				ifFalse: [ 
					| valid |
					valid := true.
					vrsnStatus
						do: [ :status | 
							(validStatusList includes: status)
								ifFalse: [ valid := false ] ].
					valid ] ]!

----- Method: MetacelloMCPartiallyLoadedStatus>>hasNoPackage (in category 'accessing') -----
hasNoPackage
	^ hasNoPackage!

----- Method: MetacelloMCPartiallyLoadedStatus>>hasNoPackage: (in category 'accessing') -----
hasNoPackage: aBoolean
	hasNoPackage := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>hasNoProject (in category 'accessing') -----
hasNoProject
	^ hasNoProject!

----- Method: MetacelloMCPartiallyLoadedStatus>>hasNoProject: (in category 'accessing') -----
hasNoProject: aBoolean
	hasNoProject := aBoolean!

----- Method: MetacelloMCPartiallyLoadedStatus>>initialize (in category 'initialization') -----
initialize
	super initialize.
	hasNoPackage := hasNoProject := true.
	aProjectIsLoaded := aPackageIsLoaded := false.
	aLoadedProjectIsExact := aLoadedPackageIsExact := false.
	aLoadedProjectIsCurrent := aLoadedPackageIsCurrent := false.
	aLoadedProjectIsNotCurrent := aLoadedPackageIsNotCurrent := false.
	aProjectNotLoaded := aPackageNotLoaded := false.
	vrsnStatus := Set new.
	abort := false!

----- Method: MetacelloMCPartiallyLoadedStatus>>isAllLoadedToSpec: (in category 'testing') -----
isAllLoadedToSpec: matchBlock
        "all projects and packages are loaded and match specification"

	(self evaluateStatus: #(#allLoadedToSpec))
		ifTrue: [ 
			((hasNoPackage
				or: [ 
					aPackageIsLoaded & aPackageNotLoaded not & aLoadedPackageIsExact & aLoadedPackageIsNotCurrent not
						& aLoadedPackageIsCurrent not ])
				and: [ 
					hasNoProject
						or: [ 
							aProjectIsLoaded & aProjectNotLoaded not & aLoadedProjectIsExact & aLoadedProjectIsNotCurrent not
								& aLoadedProjectIsCurrent not ] ])
				ifTrue: [ matchBlock value: #allLoadedToSpec ] ]!

----- Method: MetacelloMCPartiallyLoadedStatus>>isLoadedMatchConstraints: (in category 'testing') -----
isLoadedMatchConstraints: matchBlock
	"all loaded projects and packages match constraints (at least one package loaded)"

	| matchStatus |
	matchStatus := #loadedMatchConstraints.
	(self evaluateStatus: #(#allLoadedToSpec #loadedToSpec #loadedMatchConstraints))
		ifTrue: [ 
			aPackageIsLoaded & aProjectIsLoaded
				ifTrue: [ 
					(aLoadedPackageIsExact | aLoadedPackageIsCurrent & aLoadedPackageIsNotCurrent not
						and: [ aLoadedProjectIsExact | aLoadedProjectIsCurrent & aLoadedProjectIsNotCurrent not ])
						ifTrue: [ matchBlock value: matchStatus ] ]
				ifFalse: [ 
					aPackageIsLoaded
						ifTrue: [ 
							aLoadedPackageIsExact | aLoadedPackageIsCurrent & aLoadedPackageIsNotCurrent not
								ifTrue: [ matchBlock value: matchStatus ] ]
						ifFalse: [ 
							hasNoPackage & (aLoadedProjectIsExact | aLoadedProjectIsCurrent) & aLoadedProjectIsNotCurrent not
								ifTrue: [ matchBlock value: matchStatus ] ] ] ]!

----- Method: MetacelloMCPartiallyLoadedStatus>>isLoadedToSpec: (in category 'testing') -----
isLoadedToSpec: matchBlock
	"all loaded projects and packages match specifications (at least one package loaded)"

	| matchStatus |
	matchStatus := #loadedToSpec.
	(self evaluateStatus: #(#allLoadedToSpec #loadedToSpec))
		ifTrue: [ 
			aPackageIsLoaded & aProjectIsLoaded
				ifTrue: [ 
					(aLoadedPackageIsExact & aLoadedPackageIsCurrent not & aLoadedPackageIsNotCurrent not
						and: [ aLoadedProjectIsExact & aLoadedProjectIsCurrent not & aLoadedProjectIsNotCurrent not ])
						ifTrue: [ matchBlock value: matchStatus ] ]
				ifFalse: [ 
					aPackageIsLoaded
						ifTrue: [ 
							aLoadedPackageIsExact & aLoadedPackageIsCurrent not & aLoadedPackageIsNotCurrent not
								ifTrue: [ matchBlock value: matchStatus ] ]
						ifFalse: [ 
							hasNoPackage & aLoadedProjectIsExact & aLoadedProjectIsCurrent not & aLoadedProjectIsNotCurrent not
								ifTrue: [ matchBlock value: matchStatus ] ] ] ]!

----- Method: MetacelloMCPartiallyLoadedStatus>>isSomethingLoaded: (in category 'testing') -----
isSomethingLoaded: somethingLoadedBlock
	"at least one package loaded"

	(self evaluateStatus: #(#allLoadedToSpec #loadedToSpec #loadedMatchConstraints #somethingLoaded))
		ifTrue: [ 
			aPackageIsLoaded
				ifTrue: [ somethingLoadedBlock value: #somethingLoaded ] ]!

----- Method: MetacelloMCPartiallyLoadedStatus>>vrsnStatus (in category 'accessing') -----
vrsnStatus
	^vrsnStatus!

Object subclass: #MetacelloMCVersionSpecLoader
	instanceVariableNames: 'versionSpec required packages loader loaderPolicy'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Loaders'!

----- Method: MetacelloMCVersionSpecLoader class>>on: (in category 'instance creation') -----
on: aVersionSpec

	^(self new) 
		versionSpec: aVersionSpec;
		yourself!

----- Method: MetacelloMCVersionSpecLoader>>label (in category 'accessing') -----
label

	^self versionSpec label!

----- Method: MetacelloMCVersionSpecLoader>>load (in category 'loading') -----
load
  | mcLoader |
  packages := Dictionary new.
  self resolveToLoadableSpecs.
  mcLoader := self loader.
  packages values
    do: [ :pkg | 
      pkg ensureLoadedForDevelopmentUsing: mcLoader.
      (MetacelloIgnorePackageLoaded signal: pkg)
        ifFalse: [ 
          mcLoader ignoreImage
            ifFalse: [ 
              (pkg
                compareCurrentVersion: self operator
                targetVersionStatus: #(#'allLoadedToSpec')
                using: mcLoader)
                ifTrue: [ packages removeKey: pkg name ] ] ] ].
  packages notEmpty
    ifTrue: [ 
      mcLoader preLoad: self versionSpec.
      mcLoader load.
      mcLoader postLoad: self versionSpec ].
  ^ mcLoader!

----- Method: MetacelloMCVersionSpecLoader>>loader (in category 'accessing') -----
loader

	loader == nil 
		ifTrue: [
			loader := self versionSpec loader copy.
			loader spec: self.
			loaderPolicy notNil ifTrue: [ loader loaderPolicy: loaderPolicy] ].
	^loader!

----- Method: MetacelloMCVersionSpecLoader>>loaderPolicy (in category 'accessing') -----
loaderPolicy
	^ loaderPolicy!

----- Method: MetacelloMCVersionSpecLoader>>loaderPolicy: (in category 'accessing') -----
loaderPolicy: anObject
	loaderPolicy := anObject!

----- Method: MetacelloMCVersionSpecLoader>>name (in category 'accessing') -----
name

	^self versionSpec name!

----- Method: MetacelloMCVersionSpecLoader>>operator (in category 'accessing') -----
operator

	^self loader operator!

----- Method: MetacelloMCVersionSpecLoader>>packageSpecsInLoadOrder (in category 'spec compatibility') -----
packageSpecsInLoadOrder
    ^ self versionSpec packageSpecsInLoadOrderForMap: packages!

----- Method: MetacelloMCVersionSpecLoader>>packages (in category 'accessing') -----
packages

	^packages!

----- Method: MetacelloMCVersionSpecLoader>>project (in category 'accessing') -----
project

	^self versionSpec project!

----- Method: MetacelloMCVersionSpecLoader>>repositories (in category 'loading') -----
repositories

	^self repositorySpecs!

----- Method: MetacelloMCVersionSpecLoader>>repositorySpecs (in category 'spec compatibility') -----
repositorySpecs

	| repositoryMap |
	repositoryMap := self versionSpec repositories ~~ nil
		ifTrue: [ self versionSpec repositories map ]
		ifFalse: [ Dictionary new ].
	^repositoryMap values.!

----- Method: MetacelloMCVersionSpecLoader>>required (in category 'accessing') -----
required

	required == nil ifTrue: [ ^#() ].
	^ required!

----- Method: MetacelloMCVersionSpecLoader>>required: (in category 'accessing') -----
required: anObject
	required := anObject!

----- Method: MetacelloMCVersionSpecLoader>>resolvePackageNames (in category 'loading') -----
resolvePackageNames

	packages := Dictionary new.
	self resolveToLoadableSpecs.
	^packages values collect: [:pkg | pkg name ]!

----- Method: MetacelloMCVersionSpecLoader>>resolveToLoadableSpecs (in category 'private') -----
resolveToLoadableSpecs
    self versionSpec resolveToLoadableSpecs: required forLoad: true map: packages!

----- Method: MetacelloMCVersionSpecLoader>>versionSpec (in category 'accessing') -----
versionSpec
	^ versionSpec!

----- Method: MetacelloMCVersionSpecLoader>>versionSpec: (in category 'accessing') -----
versionSpec: anObject
	versionSpec := anObject!

----- Method: MetacelloMCVersionSpecLoader>>versionString (in category 'spec compatibility') -----
versionString

	^self versionSpec versionString!

Object subclass: #MetacelloVisitedPackages
	instanceVariableNames: 'groups packages projects'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloVisitedPackages>>initialize (in category 'initialize-release') -----
initialize

	groups := Set new.
	packages := Set new.
	projects := Set new.!

----- Method: MetacelloVisitedPackages>>pushProject: (in category 'visiting') -----
pushProject: aBlock

	| oldGroups oldPackages oldProjects |
	oldGroups := groups.
	oldPackages := packages.
	oldProjects := projects.
	groups := Set new.
	packages := Set new.
	^aBlock ensure: [
		groups := oldGroups.
		packages := oldPackages.
		projects := oldProjects ]!

----- Method: MetacelloVisitedPackages>>visit:doing: (in category 'visiting') -----
visit: aSpec doing: aBlock

	aSpec
		projectDo: [:spec | 
			(projects includes: spec name) ifTrue: [ ^self ].
			projects add: spec name ] 
		packageDo: [:spec | 
			(packages includes: spec name) ifTrue: [ ^self ].
			packages add: spec name ] 
		groupDo: [:spec | 
			(groups includes: spec name) ifTrue: [ ^self ].
			groups add: spec name ].
	aBlock value: aSpec!

----- Method: Object class>>lastMetacelloVersionLoad (in category '*metacello-mc') -----
lastMetacelloVersionLoad
	"Answer the last version loaded and the list of packages loaded for that version.
	 See MetacelloConfigTemplate."

	^nil -> 'default'!

----- Method: Object class>>metacelloVersion:loads: (in category '*metacello-mc') -----
metacelloVersion: versionString loads: anArrayOrString
	"Stash the last version loaded and the list of packages loaded for that version. The list
	 of packages will be used by the tools when doing 'Load Package Version'.
	See MetacelloConfigTemplate for example"
	
	"noop by default"!

----- Method: GoferResolvedReference>>asMetacelloCachingResolvedReference (in category '*metacello-mc') -----
asMetacelloCachingResolvedReference

	^MetacelloCachingGoferResolvedReference name: self name repository: self repository!

GoferResolvedReference subclass: #MetacelloCachingGoferResolvedReference
	instanceVariableNames: 'cachedVersion'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Gofer'!

----- Method: MetacelloCachingGoferResolvedReference>>version (in category 'accessing') -----
version
	"Answer a Monticello version of the receiver."

	cachedVersion == nil ifTrue: [ cachedVersion := super version ].
	^cachedVersion!

----- Method: MetacelloCachingGoferResolvedReference>>workingCopy (in category 'querying') -----
workingCopy
	"Answer a working copy or throw an error if not present."

	| pName |
	cachedVersion == nil ifTrue: [ ^super workingCopy ].
	pName := cachedVersion package name.
	^MCWorkingCopy allManagers
		detect: [ :each | pName = each packageName ]
		ifNone: [ self error: 'Working copy for ' , self name , ' not found' ]!

MetacelloProject subclass: #MetacelloMCProject
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Model'!

MetacelloMCProject subclass: #MetacelloMCBaselineProject
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Model'!

!MetacelloMCBaselineProject commentStamp: 'dkh 5/5/2012 08:47' prior: 0!
The **MetacelloMCBaselineProject**  is a wrapper for the **BaselineOf** version specification for file-based repositories.

There is a single version in a **MetacelloMCBaselineProject**, named *'baseline'*.

A typical **BaselineOf** is specification:

```Smalltalk
baseline: spec
    <baseline>
    spec
        package: 'External-Core';
        package: 'External-Tests' with: [ spec requires: 'External-Core' ];
        yourself.
    spec
        group: 'Core' with: #('External-Core');
        group: 'default' with: #('Core');
        group: 'Tests' with: #('External-Tests');
        yourself
```

The `<baseline>` pragma marks the method containing the baseline specification.!

----- Method: MetacelloMCBaselineProject class>>singletonVersionName (in category 'accessing') -----
singletonVersionName
    ^ 'baseline'!

----- Method: MetacelloMCBaselineProject class>>versionConstructorClass (in category 'accessing') -----
versionConstructorClass
    ^ MetacelloBaselineConstructor!

----- Method: MetacelloMCBaselineProject>>asBaselineProject (in category 'scripting') -----
asBaselineProject
    ^ self!

----- Method: MetacelloMCBaselineProject>>asConfigurationProject (in category 'scripting') -----
asConfigurationProject
    ^ MetacelloMCProject new!

----- Method: MetacelloMCBaselineProject>>bleedingEdge (in category 'versions') -----
bleedingEdge
    ^ nil!

----- Method: MetacelloMCBaselineProject>>currentVersion (in category 'versions') -----
currentVersion
    ^ self version isSomethingLoaded
        ifTrue: [ self version ]
        ifFalse: [ nil ]!

----- Method: MetacelloMCBaselineProject>>currentVersionAgainst: (in category 'versions') -----
currentVersionAgainst: resolvedPackageAndProjectNames
    ^ nil!

----- Method: MetacelloMCBaselineProject>>development (in category 'versions') -----
development
    ^ nil!

----- Method: MetacelloMCBaselineProject>>hasVersion: (in category 'versions') -----
hasVersion: versionString
    ^ versionString = 'baseline'!

----- Method: MetacelloMCBaselineProject>>lastVersion (in category 'versions') -----
lastVersion
    ^ self version!

----- Method: MetacelloMCBaselineProject>>latestVersion (in category 'versions') -----
latestVersion
    ^ self version!

----- Method: MetacelloMCBaselineProject>>latestVersion: (in category 'versions') -----
latestVersion: blessing
    ^ nil!

----- Method: MetacelloMCBaselineProject>>latestVersionMatching: (in category 'versions') -----
latestVersionMatching: versionPatternString
    ^ nil!

----- Method: MetacelloMCBaselineProject>>latestVersionMatching:excludedBlessings: (in category 'versions') -----
latestVersionMatching: versionPatternString excludedBlessings: excluded
    ^ nil!

----- Method: MetacelloMCBaselineProject>>latestVersionMatching:includedBlessings: (in category 'versions') -----
latestVersionMatching: versionPatternString includedBlessings: included
    ^ nil!

----- Method: MetacelloMCBaselineProject>>latestVersionMatching:includedBlessings:excludedBlessings: (in category 'versions') -----
latestVersionMatching: versionPatternString includedBlessings: included excludedBlessings: excludedBlessings
    ^ nil!

----- Method: MetacelloMCBaselineProject>>projectForScriptEngine:unconditionalLoad: (in category 'scripting') -----
projectForScriptEngine: aMetacelloScriptEngine unconditionalLoad: aBool
  "see https://github.com/dalehenrich/metacello-work/issues/244 ... uncoditionally load
   baseline"

  ^ aMetacelloScriptEngine getBaselineProjectUnconditionalLoad: true!

----- Method: MetacelloMCBaselineProject>>setBaselineRepositoryDescription: (in category 'as yet unclassified') -----
setBaselineRepositoryDescription: aListOrRepositoryDescriptions
    "set #version repositories to < aListOrRepositoryDescriptions>. Should be the directory where the BaselineOf is located."

    aListOrRepositoryDescriptions do: [:desc | self version spec repository: desc]!

----- Method: MetacelloMCBaselineProject>>singletonVersionName (in category 'versions') -----
singletonVersionName
    ^ self class singletonVersionName!

----- Method: MetacelloMCBaselineProject>>stableVersion (in category 'versions') -----
stableVersion
    ^ nil!

----- Method: MetacelloMCBaselineProject>>symbolicVersionSymbols (in category 'versions') -----
symbolicVersionSymbols
    ^ nil!

----- Method: MetacelloMCBaselineProject>>version (in category 'versions') -----
version
    ^ self version: self singletonVersionName!

----- Method: MetacelloMCBaselineProject>>versions (in category 'versions') -----
versions
  ^ [ {(self version)} ]
    on: MetacelloVersionDoesNotExistError
    do: [ :ex | ^ #() ]!

----- Method: MetacelloMCProject>>asBaselineProject (in category 'scripting') -----
asBaselineProject
    ^ MetacelloMCBaselineProject new!

----- Method: MetacelloMCProject>>asConfigurationProject (in category 'scripting') -----
asConfigurationProject
    ^ self!

----- Method: MetacelloMCProject>>baselineOfProjectSpecClass (in category 'spec classes') -----
baselineOfProjectSpecClass
    ^ MetacelloMCBaselineOfProjectSpec!

----- Method: MetacelloMCProject>>configurationOfProjectSpecClass (in category 'spec classes') -----
configurationOfProjectSpecClass
    ^ MetacelloMCConfigurationOfProjectSpec!

----- Method: MetacelloMCProject>>createRepository: (in category 'repository creation') -----
createRepository: aRepositorySpec

	^ MetacelloPlatform current createRepository: aRepositorySpec!

----- Method: MetacelloMCProject>>defaultLoaderClass (in category 'spec classes') -----
defaultLoaderClass

	^MetacelloLoadingMCSpecLoader!

----- Method: MetacelloMCProject>>fetchProject (in category 'development support') -----
fetchProject
	"fetch the latest version of the configuration package"
	
	^self fetchProject: MetacelloLoaderPolicy new!

----- Method: MetacelloMCProject>>fetchProject: (in category 'development support') -----
fetchProject: aLoaderPolicy
	"fetch the latest version of the configuration package"
	
	| mcLoader |
	(mcLoader := self loader) == nil
		ifTrue: [ mcLoader := self project loaderClass on: nil ].
	mcLoader loaderPolicy: aLoaderPolicy.
	mcLoader doingLoads: [ 
		MCWorkingCopy
			managersForClass: self configuration class
			do: [:mgr | | pkg |
				pkg := self packageSpec.
				mgr repositoryGroup repositories do: [:repo | pkg repositories repository: (repo asRepositorySpecFor: self) ].
				pkg name: mgr packageName.
				pkg fetchUsing: mcLoader.
				^true ]].
	^true!

----- Method: MetacelloMCProject>>goferBranch:project: (in category 'development support') -----
goferBranch: branchName project: commitMessage
    | pkgSpec |
    pkgSpec := self projectPackage.
    pkgSpec file: pkgSpec name , '.' , branchName.
    ^ pkgSpec goferBranchPackage: branchName message: commitMessage!

----- Method: MetacelloMCProject>>goferCommitProject: (in category 'development support') -----
goferCommitProject: commitMessage

	| pkgSpec |
	(pkgSpec := self projectPackage) == nil ifTrue: [ ^false ].
	^pkgSpec goferCommitPackage: commitMessage!

----- Method: MetacelloMCProject>>packageSpec (in category 'spec classes') -----
packageSpec

	^self packageSpecClass for: self!

----- Method: MetacelloMCProject>>packageSpecClass (in category 'spec classes') -----
packageSpecClass

	^MetacelloPackageSpec!

----- Method: MetacelloMCProject>>packagesNeedSaving: (in category 'development support') -----
packagesNeedSaving: aVersionString
	"Answer a collection of associations (package -> repository) representing the packages 
	 reachable from this project that need to be saved"

	| packages |
	packages := Set new.
	(self version: aVersionString) spec 
		packagesNeedSavingVisited: (Set with: self configuration class name asString)
		into: packages.
	^packages!

----- Method: MetacelloMCProject>>pragmaKeywords (in category 'private') -----
pragmaKeywords

	^super pragmaKeywords, #(projectPackage:attribute: packages:attribute: repositories:attribute: )!

----- Method: MetacelloMCProject>>projectForScriptEngine:unconditionalLoad: (in category 'scripting') -----
projectForScriptEngine: aMetacelloScriptEngine unconditionalLoad: aBool
    ^ aMetacelloScriptEngine getConfigurationProjectUnconditionalLoad: aBool!

----- Method: MetacelloMCProject>>projectPackage (in category 'development support') -----
projectPackage
  MCWorkingCopy
    managersForClass: self configuration class
    do: [ :mgr | 
      | pkgSpec repo |
      pkgSpec := self packageSpec
        name: mgr packageName;
        yourself.
      mgr ancestors notEmpty
        ifTrue: [ pkgSpec file: mgr ancestors first name ].
      repo := mgr repositoryGroup repositories
        detect: [ :each | each ~~ MetacelloPlatform current defaultPackageCache ]
        ifNone: [ 
          Transcript
            cr;
            show:
                'Using cache repository for ' , self label , ' project package'.
          MetacelloPlatform current defaultPackageCache ].
      pkgSpec repository: (repo asRepositorySpecFor: self).
      ^ pkgSpec ].
  ^ nil!

----- Method: MetacelloMCProject>>projectSpecClass (in category 'spec classes') -----
projectSpecClass
	^ MetacelloMCNamelessProjectSpec!

----- Method: MetacelloMCProject>>repositoriesSpec (in category 'spec classes') -----
repositoriesSpec

	^self repositoriesSpecClass for: self!

----- Method: MetacelloMCProject>>repositoriesSpecClass (in category 'spec classes') -----
repositoriesSpecClass

	^MetacelloRepositoriesSpec!

----- Method: MetacelloMCProject>>repositorySpec (in category 'spec classes') -----
repositorySpec

	^self repositorySpecClass for: self!

----- Method: MetacelloMCProject>>repositorySpecClass (in category 'spec classes') -----
repositorySpecClass

	^MetacelloRepositorySpec!

----- Method: MetacelloMCProject>>saveProject (in category 'development support') -----
saveProject

	| pkgSpec |
	(pkgSpec := self projectPackage) == nil ifTrue: [ ^false ].
	^pkgSpec savePackage!

----- Method: MetacelloMCProject>>setBaselineRepositoryDescription: (in category 'as yet unclassified') -----
setBaselineRepositoryDescription: aListOrRepositoryDescriptions
    "noop "!

----- Method: MetacelloMCProject>>updatePackageRepositoriesFor: (in category 'repository updating') -----
updatePackageRepositoriesFor: versionString

	| versionSpec |
	(versionSpec := (self version: versionString) versionSpec) packageSpecsInLoadOrder do: [:pkgSpec |
		pkgSpec updatePackageRepositoriesFor: versionSpec ].
	^true!

----- Method: MetacelloMCProject>>updateProject (in category 'development support') -----
updateProject
	"load the latest version of the configuration package"

	"WARNING: don't forget to refresh your project instance after doing an #updateProject, 
	 otherwise your instance won't reflect the info in the freshly loaded configuration"
	
	^self updateProject: MetacelloLoaderPolicy new!

----- Method: MetacelloMCProject>>updateProject: (in category 'development support') -----
updateProject: aLoaderPolicy
	"load the latest version of the configuration package"

	"WARNING: don't forget to refresh your project instance after doing an #updateProject, 
	 otherwise your instance won't reflect the info in the freshly loaded configuration"

	| mcLoader |
	(mcLoader := self loader) == nil
		ifTrue: [ mcLoader := self project loaderClass on: nil ].
	mcLoader loaderPolicy: aLoaderPolicy.
	mcLoader
		doingLoads: [ 
			MCWorkingCopy
				managersForClass: self configuration class
				do: [ :mgr | 
					| pkg ar |
					pkg := self packageSpec.
					mgr repositoryGroup repositories do: [ :repo | pkg repositories repository: (repo asRepositorySpecFor: self) ].
					ar := mgr metacelloPackageNameWithBranch.
					pkg name: (ar at: 1).
					(ar at: 2) notEmpty
						ifTrue: [ pkg file: (ar at: 2) ].
					pkg load.
					^ true ] ].
	^ true!

----- Method: MetacelloMCProject>>versionSpecClass (in category 'spec classes') -----
versionSpecClass

	^MetacelloMCVersionSpec!

----- Method: MCVersionLoader>>versions (in category '*metacello-mc') -----
versions

	^versions!

----- Method: GoferVersionReference>>compare:using: (in category '*metacello-mc') -----
compare: aLoadableReference using: aComparisonOperator
	"Compare versions using <aComparisonOperator>. package names #= then compare based upon version number
	Branches and Author names are used in the case of a version number tie, because we need to avoid seesaw loading."
		
	self packageName = aLoadableReference packageName
		ifFalse: [ ^false ].
	self versionNumber = aLoadableReference versionNumber
		ifFalse: [ ^ self versionNumber perform: aComparisonOperator with: aLoadableReference versionNumber ].
	self branch = aLoadableReference branch 
		ifFalse: [ ^ self branch perform: aComparisonOperator with: aLoadableReference branch ].
	^ self author perform: aComparisonOperator with: aLoadableReference author!

----- Method: GoferVersionReference>>matchesMetacelloGoferPackage: (in category '*metacello-mc') -----
matchesMetacelloGoferPackage: aMetacelloGoferPackage
  | ref |
  (super matchesMetacelloGoferPackage: aMetacelloGoferPackage)
    ifFalse: [ ^ false ].
  ref := self class name: aMetacelloGoferPackage packageFilename.
  ref versionNumber = 0
    ifTrue: [ ^ true ].
  ^ self versionNumber = ref versionNumber!

----- Method: GoferVersionReference>>metacelloPackageNameWithBranch (in category '*metacello-mc') -----
metacelloPackageNameWithBranch
	"answer array with package name and package name with branch name"
	self branch isEmpty
		ifTrue: [ 
			^ {(self packageName).
			(self packageName)} ].
	^ {(self packageName).
	(self packageName , '.' , self branch)}!

MetacelloVersionSpec subclass: #MetacelloMCVersionSpec
	instanceVariableNames: 'repositories packages'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloMCVersionSpec>>computeVersionStatus: (in category 'accessing') -----
computeVersionStatus: matchBlock
	self computeVersionStatus: (self expandToLoadableSpecNames: #('ALL')) matchBlock: matchBlock!

----- Method: MetacelloMCVersionSpec>>computeVersionStatus:matchBlock: (in category 'accessing') -----
computeVersionStatus: resolvedPackageAndProjectNames matchBlock: matchBlock
	| status |
	status := resolvedPackageAndProjectNames isNil
		ifTrue: [ self isPartiallyCurrent ]
		ifFalse: [ self isPartiallyCurrentAgainst: resolvedPackageAndProjectNames ].
	status isAllLoadedToSpec: matchBlock.
	status isLoadedToSpec: matchBlock.
	status isLoadedMatchConstraints: matchBlock.
	status isSomethingLoaded: matchBlock!

----- Method: MetacelloMCVersionSpec>>configMethodOn:last:indent: (in category 'printing') -----
configMethodOn: aStream last: last indent: indent
    | spec hasRepositories hasPackageSpecs hasImport |
    hasRepositories := (spec := self repositoriesSpec) ~~ nil and: [ spec list isEmpty not ].
    hasImport := self import ~~ nil.
    hasPackageSpecs := false.
    self packagesSpec list
        do: [ :member | 
            member spec
                projectDo: [ :proj | 
                    member spec name ~~ nil
                        ifTrue: [ hasPackageSpecs := true ] ]
                packageDo: [ :package | 
                    member spec name ~~ nil
                        ifTrue: [ hasPackageSpecs := true ] ]
                groupDo: [ :group | 
                    member spec name ~~ nil
                        ifTrue: [ hasPackageSpecs := true ] ] ].
    self configMethodBasicOn: aStream last: (hasRepositories | hasPackageSpecs | hasImport) not indent: indent.
    hasImport
        ifTrue: [ 
            self
                configMethodValueOn: aStream
                for: self import
                selector: 'import:'
                last: (hasRepositories | hasPackageSpecs) not
                indent: indent ].
    hasRepositories
        ifTrue: [ 
            spec map values size = 1
                ifTrue: [ 
                    aStream
                        tab: indent;
                        nextPutAll: 'spec repository: ';
                        nextPutAll: spec map values first description printString , '.'.
                    hasPackageSpecs
                        ifTrue: [ aStream cr ] ]
                ifFalse: [ 
                    self
                        configMethodOn: aStream
                        for: spec
                        selector: 'repositories:'
                        last: hasPackageSpecs not
                        indent: indent ] ].
    self configPackagesSpecMethodOn: aStream indent: indent.
    last
        ifFalse: [ aStream cr ]!

----- Method: MetacelloMCVersionSpec>>configSpawnMethodOn:indent: (in category 'printing') -----
configSpawnMethodOn: aStream indent: indent

	super configSpawnMethodOn: aStream indent: indent.
	self configPackagesSpecMethodOn: aStream indent: indent.!

----- Method: MetacelloMCVersionSpec>>currentlyLoadedClassesInVersion (in category 'querying') -----
currentlyLoadedClassesInVersion
  | classes |
  classes := Set new.
  self
    projectDo: [ :ignored |  ]
    packageDo: [ :packageSpec | 
      | wc |
      wc := [ packageSpec workingCopy ]
        on: Error
        do: [ :ex | ex return: nil ].
      wc ~~ nil
        ifTrue: [ classes addAll: (MetacelloPlatform current packageInfoFor: wc) classes ] ]
    groupDo: [ :ignored |  ].
  ^ classes!

----- Method: MetacelloMCVersionSpec>>currentlyLoadedExtensionClassesInVersion (in category 'querying') -----
currentlyLoadedExtensionClassesInVersion
  | classes |
  classes := Dictionary new.
  self
    projectDo: [ :ignored |  ]
    packageDo: [ :packageSpec | 
      | wc |
      wc := [ packageSpec workingCopy ]
        on: Error
        do: [ :ex | ex return: nil ].
      wc ~~ nil
        ifTrue: [ 
          | packageInfo |
          packageInfo := MetacelloPlatform current packageInfoFor: wc.
          packageInfo extensionClasses
            do: [ :cl | classes at: cl put: (packageInfo extensionCategoriesForClass: cl) ] ] ]
    groupDo: [ :ignored |  ].
  ^ classes!

----- Method: MetacelloMCVersionSpec>>difference: (in category 'querying') -----
difference: otherVersionSpec
    "Return a dictionary of additions, removals and modifications"

    | report myProjectSpecs myPackageSpecs otherProjectSpecs otherPackageSpecs |
    report := MetacelloVersionDiffReport new.
    myProjectSpecs := Dictionary new.
    myPackageSpecs := Dictionary new.
    self
        projectDo: [ :projectSpec | myProjectSpecs at: projectSpec name put: projectSpec ]
        packageDo: [ :packageSpec | myPackageSpecs at: packageSpec name put: packageSpec ]
        groupDo: [ :ignored |  ].
    otherProjectSpecs := Dictionary new.
    otherPackageSpecs := Dictionary new.
    otherVersionSpec
        projectDo: [ :projectSpec | otherProjectSpecs at: projectSpec name put: projectSpec ]
        packageDo: [ :packageSpec | otherPackageSpecs at: packageSpec name put: packageSpec ]
        groupDo: [ :ignored |  ].
    myProjectSpecs
        valuesDo: [ :myProjectSpec | 
            | otherProjectSpec |
            otherProjectSpec := otherProjectSpecs at: myProjectSpec name ifAbsent: [  ].
            otherProjectSpec == nil
                ifTrue: [ 
                    report removals
                        at: myProjectSpec name
                        put:
                            {(myProjectSpec versionString).
                            ''} ]
                ifFalse: [ 
                    myProjectSpec versionString = otherProjectSpec versionString
                        ifFalse: [ 
                            report modifications
                                at: myProjectSpec name
                                put:
                                    {(myProjectSpec versionString).
                                    (otherProjectSpec versionString)} ] ] ].
    otherProjectSpecs
        valuesDo: [ :otherProjectSpec | 
            (myProjectSpecs at: otherProjectSpec name ifAbsent: [  ]) == nil
                ifTrue: [ 
                    report additions
                        at: otherProjectSpec name
                        put:
                            {''.
                            (otherProjectSpec versionString)} ] ].
    myPackageSpecs
        valuesDo: [ :myPackageSpec | 
            | otherPackageSpec |
            otherPackageSpec := otherPackageSpecs at: myPackageSpec name ifAbsent: [  ].
            otherPackageSpec == nil
                ifTrue: [ 
                    report removals
                        at: myPackageSpec name
                        put:
                            {(myPackageSpec file).
                            ''} ]
                ifFalse: [ 
                    myPackageSpec file = otherPackageSpec file
                        ifFalse: [ 
                            report modifications
                                at: myPackageSpec name
                                put:
                                    {(myPackageSpec file).
                                    (otherPackageSpec file)} ] ] ].
    otherPackageSpecs
        valuesDo: [ :otherPackageSpec | 
            (myPackageSpecs at: otherPackageSpec name ifAbsent: [  ]) == nil
                ifTrue: [ 
                    report additions
                        at: otherPackageSpec name
                        put:
                            {''.
                            (otherPackageSpec file)} ] ].
    ^ report!

----- Method: MetacelloMCVersionSpec>>forceUpdatedPackageSpecs (in category 'development support') -----
forceUpdatedPackageSpecs

	| updatedSpecs mcLoader |
	updatedSpecs := Dictionary new.
	mcLoader := self loader.
	self packages map valuesDo: [:pkg | pkg forceUpdatePackageSpec: updatedSpecs using: mcLoader].
	^updatedSpecs!

----- Method: MetacelloMCVersionSpec>>isAllLoadedToSpec (in category 'testing') -----
isAllLoadedToSpec
	"all projects and packages are loaded and match specification"

	self isPartiallyCurrent isAllLoadedToSpec: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isAllLoadedToSpecAgainst: (in category 'testing') -----
isAllLoadedToSpecAgainst: resolvedPackageAndProjectNames
	"all projects and packages are loaded and match specification"

	(self isPartiallyCurrentAgainst: resolvedPackageAndProjectNames) isAllLoadedToSpec: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isLoadedMatchConstraints (in category 'testing') -----
isLoadedMatchConstraints
	"all loaded projects and packages match constraints (at least one package loaded)"
	
	self isPartiallyCurrent isLoadedMatchConstraints: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isLoadedMatchConstraintsAgainst: (in category 'testing') -----
isLoadedMatchConstraintsAgainst: resolvedPackageAndProjectNames
	"all loaded projects and packages match constraints (at least one package loaded)"

	(self isPartiallyCurrentAgainst: resolvedPackageAndProjectNames) isLoadedMatchConstraints: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isLoadedToSpec (in category 'testing') -----
isLoadedToSpec
	"all loaded projects and packages match specifications (at least one package loaded)"
	
	self isPartiallyCurrent isLoadedToSpec: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isLoadedToSpecAgainst: (in category 'testing') -----
isLoadedToSpecAgainst: resolvedPackageAndProjectNames
	"all loaded projects and packages match specifications (at least one package loaded)"

	(self isPartiallyCurrentAgainst: resolvedPackageAndProjectNames) isLoadedToSpec: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isPartiallyCurrent (in category 'testing') -----
isPartiallyCurrent

	^self isPartiallyCurrentAgainst: (self expandToLoadableSpecNames: #('ALL'))!

----- Method: MetacelloMCVersionSpec>>isPartiallyCurrentAgainst: (in category 'testing') -----
isPartiallyCurrentAgainst: resolvedPackageAndProjectNames
	| mcLoader status |
	status := MetacelloMCPartiallyLoadedStatus new.
	mcLoader := self loader.
	self
		specsNamed: resolvedPackageAndProjectNames
		projectDo: [ :prj | 
			| vrsn currentVersion |
			status hasNoProject: false.
			vrsn := prj versionOrNil.
			vrsn ~~ nil
				ifTrue: [ 
					(currentVersion := prj relativeCurrentVersion) ~~ nil
						ifTrue: [ status vrsnStatus add: currentVersion versionStatus ] ].
			currentVersion ~~ nil
				ifTrue: [ 
					status aProjectIsLoaded: true.
					(currentVersion perform: #= with: vrsn)
						ifTrue: [ status aLoadedProjectIsExact: true ]
						ifFalse: [ 
							(currentVersion perform: prj projectReference operator with: vrsn)
								ifTrue: [ status aLoadedProjectIsCurrent: true ]
								ifFalse: [ status aLoadedProjectIsNotCurrent: true ] ] ]
				ifFalse: [ status aProjectNotLoaded: true ] ]
		packageDo: [ :pkg | 
			status hasNoPackage: false.
			pkg
				currentPackageLoaded: [ :versionInfos :file | 
					| wcName wcRef fileRef exact current |
					status aPackageIsLoaded: true.
					versionInfos isEmpty
						ifTrue: [ status aLoadedPackageIsNotCurrent: true ]
						ifFalse: [ 
							exact := current := false.
							versionInfos
								do: [ :vi | 
									wcName := vi name.
									fileRef := GoferResolvedReference name: file.
									wcRef := GoferResolvedReference name: wcName.
									(wcRef compare: fileRef using: #=)
										ifTrue: [ exact := true ] ].
							exact
								ifTrue: [ status aLoadedPackageIsExact: true ]
								ifFalse: [ 
									versionInfos
										do: [ :vi | 
											wcName := vi name.
											fileRef := GoferResolvedReference name: file.
											wcRef := GoferResolvedReference name: wcName.
											(wcRef compare: fileRef using: #>=)
												ifTrue: [ current := true ] ].
									current
										ifTrue: [ status aLoadedPackageIsCurrent: true ]
										ifFalse: [ status aLoadedPackageIsNotCurrent: true ] ] ] ]
				notLoaded: [ status aPackageNotLoaded: true ]
				using: mcLoader ]
		groupDo: [ :ignoredGroup | 
			"if we encounter a group, trouble"
			status abort: true.
			^ status ].
	^ status!

----- Method: MetacelloMCVersionSpec>>isPossibleBaseline (in category 'testing') -----
isPossibleBaseline

	self 
		projectDo: [:prj | prj isPossibleBaseline ifFalse: [ ^false ]] 
		packageDo: [:pkg | pkg isPackageLoaded ifFalse: [ ^false ]] 
		groupDo: [:ignored | ].
	^true!

----- Method: MetacelloMCVersionSpec>>isSomethingLoaded (in category 'testing') -----
isSomethingLoaded
	"at least one package loaded"
	
	self isPartiallyCurrent isSomethingLoaded: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>isSomethingLoadedAgainst: (in category 'testing') -----
isSomethingLoadedAgainst: resolvedPackageAndProjectNames
	"at least one package loaded"

	(self isPartiallyCurrentAgainst: resolvedPackageAndProjectNames) isSomethingLoaded: [ :ignored | ^ true ].
	^ false!

----- Method: MetacelloMCVersionSpec>>mergeMap (in category 'merging') -----
mergeMap
    | map |
    map := super mergeMap.
    map at: #'repositories' put: self repositories.
    ^ map!

----- Method: MetacelloMCVersionSpec>>mergeSpec: (in category 'merging') -----
mergeSpec: anotherSpec
    | newSpec map anotherRepositories |
    newSpec := super mergeSpec: anotherSpec.
    map := anotherSpec mergeMap.
    (anotherRepositories := map at: #'repositories') isEmpty not
        ifTrue: [ 
            newSpec
                repositories:
                    (self repositories isEmpty
                        ifTrue: [ anotherRepositories ]
                        ifFalse: [ self repositories mergeSpec: anotherRepositories ]) ].
    ^ newSpec!

----- Method: MetacelloMCVersionSpec>>nonOverridable (in category 'merging') -----
nonOverridable
    ^ super nonOverridable , #(#'repositories')!

----- Method: MetacelloMCVersionSpec>>package:constructor: (in category 'construction') -----
package: aString constructor: aVersionConstructor
    aVersionConstructor packageForVersion: aString!

----- Method: MetacelloMCVersionSpec>>package:overrides:constructor: (in category 'construction') -----
package: aString overrides: aBlock constructor: aVersionConstructor
    aVersionConstructor packageForVersion: aString overrides: aBlock!

----- Method: MetacelloMCVersionSpec>>package:with:constructor: (in category 'construction') -----
package: packageName with: aBlockOrString constructor: aVersionConstructor
    aVersionConstructor packageForVersion: packageName with: aBlockOrString!

----- Method: MetacelloMCVersionSpec>>packageNames (in category 'querying') -----
packageNames
    "leave reference to packages for upgrade purposes"

    packages == nil
        ifTrue: [ ^ super packageNames ].
    ^ self packages map keys asSet!

----- Method: MetacelloMCVersionSpec>>packageSpecsInLoadOrderForMap: (in category 'querying') -----
packageSpecsInLoadOrderForMap: packageMap
  | loadOrder pkgs packageNames importNames importSpec importProjectSpecs importProjectNameMap |
  loadOrder := self packageSpecsInLoadOrder.
  importNames := (packageNames := (packageMap values
    collect: [ :pkg | pkg name ]) asSet) copy.
  (self import isNil and: [ self importArray isNil ])
    ifTrue: [ ^ loadOrder select: [ :pkg | packageNames includes: pkg name ] ].
  loadOrder do: [ :pkg | importNames remove: pkg name ifAbsent: [  ] ].
  pkgs := OrderedCollection new.
  importProjectSpecs := Dictionary new.
  importProjectNameMap := Dictionary new.
  importArray
    ifNotNil: [ 
      loadOrder
        do: [ :pkg | 
          importArray
            do: [ :assoc | 
              assoc key = pkg name
                ifTrue: [ 
                  importProjectSpecs at: pkg name put: pkg.
                  (assoc value select: [ :each | importNames includes: each ])
                    do: [ :each | 
                      (importProjectNameMap
                        at: pkg name
                        ifAbsent: [ importProjectNameMap at: pkg name put: Set new ])
                        add: each ] ] ] ] ].
  self import
    ifNotNil: [ 
      loadOrder
        do: [ :pkg | 
          pkg name = self import
            ifTrue: [ 
              importProjectSpecs at: pkg name put: pkg.
              importProjectNameMap at: pkg name put: importNames ] ] ].
  loadOrder
    do: [ :pkg | 
      (packageNames includes: pkg name)
        ifTrue: [ pkgs add: pkg ].
      importProjectSpecs
        at: pkg name
        ifPresent: [ :importProjectSpec | 
          "insert the imports at this point"
          (importProjectNameMap at: pkg name ifAbsent: [ #() ])
            do: [ :importedName | 
              pkgs
                add:
                  (importSpec := importProjectSpec copy
                    name: importedName;
                    mergeImportLoads: {importedName};
                    yourself).
              importSpec projectReference name: importedName ] ] ].
  ^ pkgs!

----- Method: MetacelloMCVersionSpec>>packages (in category 'accessing') -----
packages
    "leave reference to packages for upgrade purposes"

    packages == nil
        ifTrue: [ ^ super packages ].
    ^ packages!

----- Method: MetacelloMCVersionSpec>>packagesNeedSavingVisited:into: (in category 'development support') -----
packagesNeedSavingVisited: visitedProjects into: aCollection

	self packages map valuesDo: [:pkg | pkg packagesNeedSavingVisited: visitedProjects using: self repositories map values into: aCollection ].!

----- Method: MetacelloMCVersionSpec>>postCopy (in category 'copying') -----
postCopy
    super postCopy.
    repositories := repositories copy.
    packages := packages copy	"leave reference to packages for upgrade purposes"!

----- Method: MetacelloMCVersionSpec>>removePackage:constructor: (in category 'construction') -----
removePackage: aString constructor: aVersionConstructor
    aVersionConstructor removePackageForVersion: aString!

----- Method: MetacelloMCVersionSpec>>repositories (in category 'accessing') -----
repositories
	repositories == nil ifTrue: [ repositories := self project repositoriesSpec ].
	^ repositories!

----- Method: MetacelloMCVersionSpec>>repositories: (in category 'accessing') -----
repositories: anObject
	repositories := anObject!

----- Method: MetacelloMCVersionSpec>>repositoriesSpec (in category 'accessing') -----
repositoriesSpec

	^self repositories!

----- Method: MetacelloMCVersionSpec>>repository: (in category 'accessing') -----
repository: aString
	self repositoriesSpec add: aString!

----- Method: MetacelloMCVersionSpec>>repository:username:password: (in category 'accessing') -----
repository: aString username: username password: password
	self repositoriesSpec repository: aString username: username password: password!

----- Method: MetacelloMCVersionSpec>>repositorySpecs (in category 'loading') -----
repositorySpecs

	^self repositories map values!

----- Method: MetacelloMCVersionSpec>>specListProjectDo:packageDo:groupDo: (in category 'enumerating') -----
specListProjectDo: projectBlock packageDo: packageBlock groupDo: groupBlock

	self packages specListDo: [:pkgSpec |
		pkgSpec projectDo: projectBlock packageDo: packageBlock groupDo: groupBlock ]!

----- Method: MetacelloMCVersionSpec>>specsNamed:projectDo:packageDo:groupDo: (in category 'enumerating') -----
specsNamed: packageAndProjectNames projectDo: projectBlock packageDo: packageBlock groupDo: groupBlock

	| map |
	map := self packages map.
	packageAndProjectNames do: [:name | | pkgSpec |
		(pkgSpec := map at: name ifAbsent: [ ]) ~~ nil
			ifTrue: [ pkgSpec projectDo: projectBlock packageDo: packageBlock groupDo: groupBlock ]]!

----- Method: MetacelloMCVersionSpec>>updateForSpawnMethod: (in category 'development support') -----
updateForSpawnMethod: sourceSpec
	"This means that this spec was used in a baseline and will be used in a version .... drop all information that isn't useful"
	
	repositories := preLoadDoIt := postLoadDoIt := nil.!

----- Method: MetacelloMCVersionSpec>>updatedPackageSpecs (in category 'development support') -----
updatedPackageSpecs

	| updatedSpecs mcLoader |
	updatedSpecs := Dictionary new.
	mcLoader := self loader.
	self packages map valuesDo: [:pkg | pkg updatePackageSpec: updatedSpecs using: mcLoader].
	^updatedSpecs!

----- Method: MetacelloMCVersionSpec>>versionClass (in category 'private') -----
versionClass

	^MetacelloMCVersion!

Gofer subclass: #MetacelloGofer
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Gofer'!

----- Method: MetacelloGofer>>basicReferencesIn: (in category 'private') -----
basicReferencesIn: aRepository
	((aRepository respondsTo: #cacheReferences) not or: [aRepository cacheReferences not])
		ifTrue: [^ super basicReferencesIn: aRepository ].
	"Use cache for network-based repositories - the contents of repository is cached based on first access 
	 and is _not_ updated afterword, so any mcz files added after the initial cache is created won't be seen"
	^ MetacelloPlatform current
		stackCacheFor: #goferRepository
		cacheClass: IdentityDictionary
		at: aRepository
		doing: [ :cache | 
			^ cache at: aRepository put: (super basicReferencesIn: aRepository) ]!

----- Method: MetacelloGofer>>interactiveCommit (in category 'operations') -----
interactiveCommit

	^ self execute: MetacelloGoferCommit!

MetacelloMemberListSpec subclass: #MetacelloRepositoriesSpec
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Metacello-MC-Specs'!

----- Method: MetacelloRepositoriesSpec>>add: (in category 'actions') -----
add: aStringOrSpec

	aStringOrSpec addToMetacelloRepositories: self!

----- Method: MetacelloRepositoriesSpec>>canUpgradeTo: (in category 'scripting') -----
canUpgradeTo: aMetacelloRepositoriesSpec
  | repositorySpecs anotherRepositorySpecs |
  repositorySpecs := self map values
    sort: [ :a :b | a description <= b description ].
  anotherRepositorySpecs := aMetacelloRepositoriesSpec map values
    sort: [ :a :b | a description <= b description ].
  repositorySpecs size ~= anotherRepositorySpecs size
    ifTrue: [ ^ false ].
  1 to: repositorySpecs size do: [ :index | 
    | repoSpec anotherRepoSpec |
    repoSpec := repositorySpecs at: index.
    anotherRepoSpec := anotherRepositorySpecs at: index.
    (repoSpec canUpgradeTo: anotherRepoSpec)
      ifTrue: [ ^ true ] ].
  ^ false!

----- Method: MetacelloRepositoriesSpec>>compareEqual: (in category 'scripting') -----
compareEqual: aMetacelloProjectSpec
    | repositorySpecs anotherRepositorySpecs |
    repositorySpecs := (self map values sort: [ :a :b | a description <= b description ])
        collect: [ :each | each description ].
    anotherRepositorySpecs := (aMetacelloProjectSpec map values sort: [ :a :b | a description <= b description ])
        collect: [ :each | each description ].
    ^ repositorySpecs = anotherRepositorySpecs!

----- Method: MetacelloRepositoriesSpec>>configMethodCascadeOn:indent: (in category 'printing') -----
configMethodCascadeOn: aStream indent: indent

	| repositorySpecs |
	repositorySpecs := self map values sort: [:a :b | a description <= b description ].
	repositorySpecs size = 1
		ifTrue: [ repositorySpecs first configMethodCascadeOn: aStream lastCascade: true ]
		ifFalse: [
			1 to: repositorySpecs size do: [:index | | repositorySpec |
				aStream tab: indent + 1.
				(repositorySpecs at: index)
					configMethodCascadeOn: aStream 
					lastCascade: index >= repositorySpecs size ]]!

----- Method: MetacelloRepositoriesSpec>>configMethodOn:indent: (in category 'printing') -----
configMethodOn: aStream indent: indent

	aStream 
		tab: indent; 
		nextPutAll: 'spec';
		cr.
	self configMethodCascadeOn: aStream indent: indent!

----- Method: MetacelloRepositoriesSpec>>hasNoLoadConflicts: (in category 'scripting') -----
hasNoLoadConflicts: aMetacelloRepositoriesSpec
  | repositorySpecs anotherRepositorySpecs |
  repositorySpecs := self map values
    sort: [ :a :b | a description <= b description ].
  anotherRepositorySpecs := aMetacelloRepositoriesSpec map values
    sort: [ :a :b | a description <= b description ].
  repositorySpecs size ~= anotherRepositorySpecs size
    ifTrue: [ ^ false ].
  1 to: repositorySpecs size do: [ :index | 
    | repoSpec anotherRepoSpec |
    repoSpec := repositorySpecs at: index.
    anotherRepoSpec := anotherRepositorySpecs at: index.
    (repoSpec hasNoLoadConflicts: anotherRepoSpec)
      ifFalse: [ ^ false ] ].
  ^ true!

----- Method: MetacelloRepositoriesSpec>>merge: (in category 'actions') -----
merge: aRepositorySpec

	aRepositorySpec mergeIntoMetacelloRepositories: self!

----- Method: MetacelloRepositoriesSpec>>metacelloRegistrationHash (in category 'scripting') -----
metacelloRegistrationHash
    ^ ((self map values sort: [ :a :b | a description <= b description ]) collect: [ :each | each description ]) hash!

----- Method: MetacelloRepositoriesSpec>>remove: (in category 'actions') -----
remove: aRepositorySpec

	aRepositorySpec removeFromMetacelloRepositories: self!

----- Method: MetacelloRepositoriesSpec>>repository: (in category 'actions') -----
repository: aStringOrSpec

	aStringOrSpec addToMetacelloRepositories: self!

----- Method: MetacelloRepositoriesSpec>>repository:constructor: (in category 'construction') -----
repository: anObject constructor: aVersionConstructor
    aVersionConstructor repositoryForRepositories: anObject!

----- Method: MetacelloRepositoriesSpec>>repository:username:password: (in category 'actions') -----
repository: description username: username password: password

	| spec |
	spec := 
		(self project repositorySpec)
			description: description;
			username: username;
			password: password;
			yourself.
	self addMember: 
		(self addMember 
			name: spec name;
			spec: spec;
			yourself)!

----- Method: MetacelloRepositoriesSpec>>repository:username:password:constructor: (in category 'construction') -----
repository: aString username: username password: password constructor: aVersionConstructor
    aVersionConstructor repositoryForRepositories: aString username: username password: password!

----- Method: MCWorkingCopy>>metacelloPackageNameWithBranch (in category '*metacello-mc') -----
metacelloPackageNameWithBranch
	"answer array with package name and package name with branch name"
	ancestry ancestors isEmpty
		ifTrue: [ 
			^ {(package name).
			(package name)} ].
	^ (GoferVersionReference name: self ancestors first name) metacelloPackageNameWithBranch!

----- Method: MCHttpRepository>>asRepositorySpecFor: (in category '*metacello-mc') -----
asRepositorySpecFor: aMetacelloMCProject

	^(aMetacelloMCProject repositorySpec)
		description:  self description;
	 	type: 'http';
		yourself!

----- Method: MCHttpRepository>>username: (in category '*metacello-mc') -----
username: aString
	"For compatibility with MetacelloRepositorySpec"

	^ self user: aString!

----- Method: MetacelloProjectReferenceSpec>>loadUsing:gofer: (in category '*metacello-mc') -----
loadUsing: aLoader gofer: ignored

	| required |
	required := self resolveToLoadableSpec.
	required loader: aLoader.
	^required load!

----- Method: MetacelloProjectReferenceSpec>>packagesNeedSavingVisited:using:into: (in category '*metacello-mc') -----
packagesNeedSavingVisited: visitedProjects using: repos into: aCollection
	
	| prjct clsName vrsn |
	prjct := self resolveToLoadableSpec.
	(visitedProjects includes: (clsName := prjct className)) ifTrue: [ ^self ].
	visitedProjects add: clsName.
	(vrsn := self versionOrNil) == nil ifTrue: [ ^self ].
	vrsn spec 
		packagesNeedSavingVisited: visitedProjects 
		into: aCollection!

----- Method: MetacelloProjectReferenceSpec>>repository: (in category '*metacello-mc') -----
repository: aStringOrMetacelloRepositorySpec
    ^ self projectReference repository: aStringOrMetacelloRepositorySpec!

----- Method: MetacelloProjectReferenceSpec>>resolveProjectSpec (in category '*metacello-mc') -----
resolveProjectSpec

	^self projectReference!

----- Method: MetacelloProjectReferenceSpec>>resolveToAllPackagesIn:into:visited: (in category '*metacello-mc') -----
resolveToAllPackagesIn: aVersionSpec into: packages visited: visited

	(self resolveProjectSpec resolveToAllPackagesIn: aVersionSpec visited: visited) do: [:pkg |
		packages at: pkg put: pkg ]!

----- Method: MetacelloProjectReferenceSpec>>resolveToLoadableSpec (in category '*metacello-mc') -----
resolveToLoadableSpec

	^self resolveProjectSpec resolveToLoadableSpec!

----- Method: MetacelloProjectReferenceSpec>>resolveToPackagesIn:andProjects:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec andProjects: andProjectsBool visited: visited
  ^ andProjectsBool
    ifTrue: [ {self} ]
    ifFalse: [ self resolveToPackagesIn: aVersionSpec visited: visited ]!

----- Method: MetacelloProjectReferenceSpec>>resolveToPackagesIn:visited: (in category '*metacello-mc') -----
resolveToPackagesIn: aVersionSpec visited: visited

	^#()!

----- Method: MetacelloProjectReferenceSpec>>updateForSpawnMethod: (in category '*metacello-mc') -----
updateForSpawnMethod: sourceSpec
	"This means that this spec was used in a baseline and will be used in a version .... drop all information that isn't useful"

	| nm |
	nm := name.
	self projectReference updateForSpawnMethod: sourceSpec.
	super updateForSpawnMethod: sourceSpec.
	name := nm.!

----- Method: MetacelloProjectReferenceSpec>>updatePackageSpec:using: (in category '*metacello-mc') -----
updatePackageSpec: updatedSpecs using: anMCLoader
	"Add project copy to updatedSpecs if the current version of the project 
	 is different from the receiver's version"
	
	self projectReference updatePackageSpec: updatedSpecs!

----- Method: MetacelloProjectReferenceSpec>>versionString (in category '*metacello-mc') -----
versionString

	^self projectReference versionString!

----- Method: MCFileBasedRepository>>versionInfoFromVersionNamed: (in category '*metacello-mc') -----
versionInfoFromVersionNamed: aString

	| versions |
	versions := self allVersionNames
		select: [ :each | each beginsWith: aString ].
	versions isEmpty ifTrue: [ ^ nil ].
	versions := versions asSortedCollection: [ :a :b |
		([ (a copyAfterLast: $.) asNumber ] on: Error do: [:ex | ex return: 0 ]) <= 
			([ (b copyAfterLast: $.) asNumber ] on: Error do: [:ex | ex return: 0 ]) ].
	^ self versionInfoFromFileNamed: versions last , '.mcz'!

----- Method: MCRepository>>asRepositorySpecFor: (in category '*metacello-mc') -----
asRepositorySpecFor: aMetacelloMCProject

	self subclassResponsibility!

----- Method: MCRepository>>cacheReferences (in category '*metacello-mc') -----
cacheReferences
	^ true!

----- Method: MCRepository>>metacelloProjectClassFor: (in category '*metacello-mc') -----
metacelloProjectClassFor: aScriptEngine
    ^ MetacelloMCProject!

----- Method: MCRepository>>projectVersion: (in category '*metacello-mc') -----
projectVersion: aString
    "noop"!



More information about the Squeak-dev mailing list