Skip to main content
Engineering LibreTexts

7.4: Gofer Actions

  • Page ID
    43830
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Loading several packages

    We can load several packages from different servers. To show you a concrete example, you have to load first the configuration of OSProcess using its Metacello configuration.

    Gofer new
        "we will load a version of the configuration of OSProcess "
        url: 'http://www.squeaksource.com/MetacelloRepository';
        package: 'ConfigurationOfOSProcess';
        load.
    
    "Now to load OSProcess you need to ask for its configuration."
    ((Smalltalk at: #ConfigurationOfOSProcess) project version: #stable) load. 
    

    The following code snippet loads multiple packages from different servers. The loading order is respected: the script loads first CollectionsArithmetic, then the necessary for Sound, and finally Phratch, a port of the well Scratch visual programming language.

    Take note that it will load the complete Phratch application, and may take a moment.

    Gofer new
        url: 'http://smalltalkhub.com/mc/PharoExtras/CollectionArithmetic/main';
        package: 'Collections-Arithmetic';
        url: 'http://smalltalkhub.com/mc/PharoExtras/Sound/main';
        package: 'Sound';
        package: 'Settings-Sound';
        package: 'SoundScores';
        package: 'SoundMorphicUserInterface';
        url: 'http://smalltalkhub.com/mc/JLaval/Phratch/main';
        package: 'Phratch';
        load
    

    This example may give the impression that Collections-Arithmetic is looked up in the CollectionArithmetic repository of the server smalltalkhub and that Phratch is looked up in the project Phratch of the smalltalkhub server. However this is not the case, Gofer does not take into account this order. In absence of version number, Gofer loads the most recent package versions found looking in the two servers.

    We can then rewrite the script in the following way:

    Gofer new
        url: 'http://smalltalkhub.com/mc/PharoExtras/CollectionArithmetic/main';
        url: 'http://smalltalkhub.com/mc/PharoExtras/Sound/main';
        url: 'http://smalltalkhub.com/mc/JLaval/Phratch/main';
        package: 'Collections-Arithmetic';
        package: 'Sound';
        package: 'Settings-Sound';
        package: 'SoundScores';
        package: 'SoundMorphicUserInterface';
        package: 'Phratch';
        load
    

    When we want to specify that package should be loaded from a specific server, we should write multiple scripts.

    Gofer new
        url: 'http://smalltalkhub.com/mc/PharoExtras/CollectionArithmetic/main';
        package: 'Collections-Arithmetic';
        load.
    Gofer new
        url: 'http://smalltalkhub.com/mc/PharoExtras/Sound/main';
        package: 'Sound';
        package: 'Settings-Sound';
        package: 'SoundScores';
        package: 'SoundMorphicUserInterface';
        load.
    Gofer new
        url: 'http://smalltalkhub.com/mc/JLaval/Phratch/main';
        package: 'Phratch';
        load
    

    Note that such scripts load the latest versions of the packages and are therefore fragile, because if a new package version is published, you will load it even if this is unstable. In general it is a good practice to control the version of the external components we rely on and use the latest version for our own current development. Now, such problem can be solved with Metacello, the tool to express configurations and load them.

    Other Protocols

    Gofer supports also FTP as well as loading from a local directory. We basically use the same messages as before, with some changes.

    For FTP, we should specify the URL using 'ftp' as the heading.

    Gofer new
        url: 'ftp://wtf-is-ftp.com/code';
        ...
    

    To work on a local directory, the message directory: followed by the absolute path of the directory should be used. Here we specify that the directory to use is reachable at /home/pharoer/hacking/MCPackages.

    Gofer new
        directory: '/home/pharoer/hacking/MCPackages';
    

    Finally it is possible to look for packages in a repository and all its subfolders using the keen star.

    Gofer new
        directory: '/home/pharoer/hacking/MCPackages/*';
        ...
    

    Once a Gofer instance is parametrized, we can send it messages to perform different actions. Here is a list of the possible actions. Some of them are described later.

    Table \(\PageIndex{1}\): Gofer actions.
    load Load the specified packages.
    update Update the package loaded versions.
    merge Merge the distant version with the one currently loaded.
    localChanges Show the list of changes between the basis version and the version currently modified.
    remoteChanges Show the changes between the version currently modified and the version published on a server.
    cleanup Cleanup packages: Obsolete system information is cleaned.
    commit / commit: Save the packages to a distant server – with a message log.
    revert Reload previously loaded packages.
    recompile Recompile packages
    unload Unload the packages from the image
    fetch Download the remote package versions from a remote server to the local cache.
    push Upload the versions from the local cache to the remote server.

    Working with remote servers

    Since Monticello is a distributed versioning control system, it is often useful to synchronize versions published on a remote server with the ones locally published in the MC local cache. Here we show the main operations to support such tasks.

    Merge, update and revert operations. The message merge performs a merge between a remote version and the working copy (the one currently loaded).

    Changes present in the working copy are merged with the code of the remote copy. It is often the case that after a merge, the working copy gets dirty and should be republished. The new version will contain the current changes and the changes of the remote version. In case of conflicts the user will be warned or else the operation will happen silently.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        merge
    

    The message update loads the remote version in the image. The modifications of the working copy are lost.

    The message revert resets the local version, i.e., it loads the current version again. The changes of the working copy are then lost.

    The commit and commit: operations. Once we have merged or changed a package we want to save it. For this we can use the messages commit and commit:. The second one is expecting a comment - in general this is a good practice.

    Gofer new
        "We save the package in the repository"
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        "We comment the changes and save"
        commit: 'I try to use the message commit: ' 
    

    The localChanges and remoteChanges operations. Before loading or saving a version, it is often useful to verify the changes made locally or on the server. The message localChanges shows the changes between the last loaded version and the working copy. The remoteChanges shows the differences between the working copy and the last published version on the server. Both return a list of changes.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        "We check that we will publish only our changes by comparing local changes versus
            the packages published on the server"
        localChanges 
    

    Using the messages browseLocalChanges and browseRemoteChanges, it is possible to browse the changes using a normal code browser.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        "we add the latest version of PBE2GoferExample"
        package: 'PBE2GoferExample';
        "we browse the latest version published on the server"
        browseRemoteChanges
    

    The unload operation. The message unload unloads the packages from the image. Note that using the Monticello browser you can delete a package, but such an operation does not remove the code of the classes associated with the package, it just destroys the package. Unloading a package destroys the packages and the classes it contains.

    The following code unloads the packages and its classes from the current image.

    Gofer new
        package: 'PBE2GoferExample';
        unload
    

    Note that you cannot unload Gofer itself that way. Gofer gofer unload does not work.

    Fetch and push operations. Since Monticello is a distributed versioning system, it is a good idea to save all the versions you want locally, without being forced to published on a remote server. This is especially true when working off-line. As it is tedious to synchronize all the local and remote published packages, the messages fetch and push are there to support you in this task.

    The message fetch copies the packages that are missing from the remote server in your local server. The packages are not loaded in Pharo. After a fetch you can load the packages even if the remote server breaks down.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        fetch
    

    Now, if you want to load your packages locally remember to set up the lookup so that it takes into account the local cache and disables errors as presented in the beginning of this chapter (messages disableRepositoryErrors and enablePackageCache).

    The message push performs the inverse operation. It publishes locally available packages to the remote server. All the packages that you published locally are then pushed to the server.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        push
    

    As a pattern, we always keep the copies of all the versions of our projects or the projects we used in our local cache. This way we are autonomous from any network failure and the packages are backed up in our regular backup.

    With these two messages, it is easy to write a script sync that synchronizes local and remote repositories.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        push.
    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        fetch
    

    As mentioned earlier, you can have multiple packages to be pushed and fetched from.

    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        package: 'PBE2GoferExampleSecondPackage';
        push.
    Gofer new
        smalltalkhubUser: 'PharoBooks' project: 'GoferExample';
        package: 'PBE2GoferExample';
        package: 'PBE2GoferExampleSecondPackage';
        fetch
    

    Automating Answers

    Sometimes package installation asks for information such as passwords. With the systematic use of a build server, packages will probably stop to do that, but it is important to know how to supply answers from within a script to these questions. The message valueSupplyingAnswers: supports such a task.

    [ Gofer new
        squeaksource: 'Seaside30';
        package: 'LoadOrderTests';
        load ]
        valueSupplyingAnswers: {
            {'Load Seaside'. True}.
            {'SqueakSource User Name'. 'pharoUser'}.
            {'SqueakSource Password'. 'pharoPwd'}.
            {'Run tests'. false}.
        } 
    

    This message should be sent to a block, giving a list of questions and their answers as shown in previous examples

    Configuration Loading

    Gofer also supports Metacello configuration loading. It provides a set of the following messages to handle configurations: configurationOf:, loadVersion:, loadDevelopment, and loadStable.

    In this example, loading the development version of NativeBoost. There you need only to specify the NativeBoost project and you will load the ConfigurationOfNativeBoost and execute the loading the development version.

    Gofer new
        smalltalkhubUser: 'Pharo' project: 'NativeBoost';
        configuration;
        loadDevelopment
    

    When the repository name does not match the name of the configuration you should use configurationOf: and provide the name of the configuration class.


    This page titled 7.4: Gofer Actions is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.