Introduction ============ Sake-Core -- is an attempt to provide similar functionality to Make and Rake, only using Smalltalk as the DSL. Sake-Packages -- is a reimplementation of Universes functionality, using Sake. It allows the metadata, load script, and unload script for a package to be defined as a Task. Sake-Scheduler -- provides the ability to register tasks to be performed periodically. Sake-Bob -- is a tool for building and testing images. (wip) Basics ====== Tasks are typically defined class side, but can be added to any class in the image. A typical task definition follows. MakeTheTea classSide >> #taskMakeTea SakeTask define: [ :task | task dependsOn: { MakeTheTea taskBoilWater. }. task if: [ Cup isEmpty ]. task action: [ Cup add: 'tea'; add: 'water'. ]. ]. To run the task: MakeTheTea taskMakeTea run. Alternatively #runStepping, or #runLogging are available for debugging. The main structure of a sake task is defined by #dependsOn: (or #addDependency:) , #if: , #action: (or #addAction:). These can all take either blocks, or lists of tasks, or lists of blocks. To see the heirarchy of tasks that will be traversed. MakeTheTea taskMakeTea what explore. Run Order ========= There are two algorithms available for determining task run order. (Further algorithms could be defined in order to support parallelism in processing.) Given a single top level task, standard Rake ordering, simply runs all the dependancies first, for every task. However Sake-Bob, when given a list of things to do, has to analyse the dependencies to determine which needs to go first. (Universes does this) Parameters ========== Unlike Rake, tasks can be defined in terms of parameters. The typical unparametized tasks found in Rake, #taskCreateMyStartingDirectory, can be written more generically as: #taskCreateStartingDirectory: name. e.g. task dependsOn: { self taskCreateStartingDirectory: 'wip' }. Class Tasks =========== In the following examples #Cup is used where the class Cup, is not guaranteed to exist. task dependsOn:{ (SakeTask class: #Cup) exists } "create a needed class" task dependsOn:{ (SakeTask class: Object) subclass: #Cup } "create a needed class" task dependsOn:{ (SakeTask class: Object) subclass: #Cup category:'Demo'} task dependsOn:{ (SakeTask class: #Cup) removeSelector: #tmp } task dependsOn:{ (SakeTask class: #Cup) removeSelectorsMatching: '*' } task dependsOn:{ (SakeTask class: #Cup) removeSelectorsMatching: '*' } task dependsOn:{ (SakeTask class: #Cup) ifExistsDo: [ :c | c rename: #Glass ] } MetaData ======== Each Sake task contains a dictionary, SakeInfo that can be used simply to store any arbitrary metadata. task info someField: someValue. Sake-Packages uses metadata extensively, in this case the typical use pattern is begin with a subclass of SakeTask and to define the generic task on the class side and the metadata on the instance side. SakeTask subclass: MakeADrink. MakeADrink classSide >> #taskPourADrink: aDrink self define: [ :task | task perform: aDrink. task if: [ Bar containsBottle: task info name ]. task action: [ Glass add: (task info name). ]. ]. Documentation Methods ===================== Subclasses of SakeTask, utilise a specialised compiler, which allows raw text to be stored in instance side methods following six quotes. """""" aTaskClass at: selector category: cat putMethod: code doc: content aTaskClass docAt: selector. This is used by the Mantis package to pull raw data from mantis, so that subsequent tasks can process that data. SakeSignal and trace: ===================== If a task needs to communicate with the outside context, it can sends a SakeSignal, a utility method is provided for this. task lookup: #aSelector. The outside context can return a value, by defining an exception handler for SakeSignal. The default implementation of #trace: is used in Sake-Tests for a task to signal to the outside testing context what it is doing. Tasks send #trace: and the SakeTaskTest runCaseWith: block, defines an exception handler to collect the signalled values so as to record the actions of the tasks. For the tests to pass all of the required actions must have been signalled. SakeStep and SakeStop ===================== task step: 'Are you Sure'. Signals a notifier to request confirmation. task stop: 'It Broke'. Finishes processing. Task Extensions =============== In the same manner as magritte. A class side task definition may be extended by another package. #taskDoThis, may be extended by adding the extension method, #taskDoThisAndAlso: task. task addDependency: [ ... ]. task addAction: [...]. Answering Notifications ======================= Tasks are wrapped in notification handlers, to use them: task answer: '*password*' with: 'secret'. ================================ Sake. Below is a SakeTask as generated from the universes package definition. What follows is a "method", in the class PackagesSqueak310U. So here is a Sake Task Definition for Seaside.... (info is simply a dictionary for non-essential meta information) ---------- PackagesSqueak310U -i- Seaside self name: 'Seaside'. info category: 'Web Development'. info description: 'A framework for building sophisticated web applications in Squeak. Develop for the web using reusable, embeddable components and unique call/return semantics for moving between pages.'. info maintainer: 'Lukas Renggli <renggli@gmail.com>'. info homepage: 'http://www.seaside.st/'. info squeakMapID: ''. info url: 'http://www.squeaksource.com/Seaside/Seaside2.8a1-lr.522.mcz'. info version: '2.8.522'. info provides: #(). self dependsOn: #('KomHttpServer'). self load: [ Installer installUrl:'http://www.squeaksource.com/Seaside/Seaside2.8a1-lr.522.mcz'. ]. self unloadDependsOn: { self taskUnloadDependants }. self unload: [ Installer unload: 'Seaside'. ]. ------------- Notice that we have an unload block as well as a load block! This is a new and very experimental feature, we can now define unload scripts for each package, and Sake/Packages provides a way to capture and publish them for some or all image versions. Indeed this feature is barely tested, I mention it here simply to intoduce the concept. usage: PackagesSqueak310 new Seaside load. or, (PackagesSqueak310 named:'Seaside') load. PackagesSqueak310 new Seaside unload. or, (PackagesSqueak310 named:'Seaside') unload. Packages/Sake is also supported by Installer in a manner similar to universes support, e.g. Installer sake addPackage: 'PackagesA'; addPackage: 'PackageB'; install. enjoy... best regards Keith p.s. to load Installer install: 'Packages'. ========== Addendum: Sake/Packages no longer uses blocks as standard, but the principle is the same.