Skip to end of metadata
Go to start of metadata

<ol>
<li><ac:link ac:anchor="distribution"><ac:link-body>Module Distribution</ac:link-body></ac:link></li>
<li><ac:link ac:anchor="installation"><ac:link-body>Module Installation</ac:link-body></ac:link></li>
<li><ac:link ac:anchor="upgrades"><ac:link-body>Module Upgrades</ac:link-body></ac:link></li>
<li><ac:link ac:anchor="fetch-install"><ac:link-body>Module Fetch+Install</ac:link-body></ac:link></li>
<li><ac:link ac:anchor="remove-downgrade"><ac:link-body>Module Removal and Downgrades</ac:link-body></ac:link></li>
<li><ac:link ac:anchor="other-considerations"><ac:link-body>Other Considerations</ac:link-body></ac:link></li>
<li><ac:link ac:anchor="community-pyrus-channel"><ac:link-body>Community Pyrus Channel</ac:link-body></ac:link></li>
</ol>

<p><ac:macro ac:name="anchor"><ac:default-parameter>distribution</ac:default-parameter></ac:macro></p>
<h2>Module Distribution (Fetching from distribution sources)</h2>

<p>The first step for installing a module is of course, fetching the module code from the distribution source and placing it in the desired location. This process can always be done manually, and does not involve triggering any sort of installation methods on the module being fetched. Locations from which modules may be fetched could include: a Git repository, a Pyrus channel, HTTP/FTP/SFTP, a local path, etc. A CLI wrapper could be provided for the task of fetching modules from common sources. By default, this command might fetch a module into the directory the command is ran from; but we could also allow an optional destination parameter to be specified.</p>

<h3>Pyrus repository</h3>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module fetch FooModule]]></ac:plain-text-body></ac:macro>
<p>This will acquire FooModule from the default configured Pyrus repository. Users would be able to easily add additional third-party Pyrus channels. In the case that multiple repositories are configured and the primary repository does not contain the package, it should proceed to check the third part repositories in the same manner as Linux package managers (yum, apt, pacman, etc).</p>

<h3>Git</h3>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module fetch git://github.com/JaneDoe/FooModule.git]]></ac:plain-text-body></ac:macro>
<p>This method would require Git to be installed. This will clone FooModule, and check out either the latest tag, or the master branch if no tags are available. If no tags are available, we may want to emit a warning that they'll be running off of master. Alternatively, a branch or tag could be specified:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module fetch git://github.com/JaneDoe/FooModule.git -b v1.2.1]]></ac:plain-text-body></ac:macro>
<p>This is basically a wrapper to `git clone`</p>

<h3>HTTP</h3>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module fetch http://somesite/modules/FooModule.phar]]></ac:plain-text-body></ac:macro>
<p>This will download the phar archive (module) into the current directory. A destination path could also be specified last. This is basically wrapper to wget/curl.</p>

<h3>Local</h3>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module fetch /path/to/local/module]]></ac:plain-text-body></ac:macro>
<p>This will copy the module from a local directory to the current directory. A destination path could also be specified. This is basically a wrapper to `cp -R`</p>

<p><ac:macro ac:name="anchor"><ac:default-parameter>installation</ac:default-parameter></ac:macro></p>
<h2>Module Installation</h2>

<p>Many modules may need to ensure that certain things such as a db connection is configured and schema installed, or perhaps that some public assets are copied into the application's plublic directory (or web server aliases, symlinks, etc are in place). This installation process would be triggered via the CLI:</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module init ./modules/MyModule]]></ac:plain-text-body></ac:macro>

<p>If the module is "installable" and has not yet been installed for this application, we would run the MyModule\Module::install() method. The `zf module init` method assumes that a module has already been fetched from the distribution source and resides locally.</p>

<p><ac:macro ac:name="anchor"><ac:default-parameter>upgrades</ac:default-parameter></ac:macro></p>
<h2>Module Upgrades</h2>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module upgrade ./modules/MyModule]]></ac:plain-text-body></ac:macro>
<p>This would trigger MyModule\Module::upgrade(). First, it may also check the original distribution source (such as Git, Pyrus, etc) for updates if it retains such information somehow.</p>

<p><ac:macro ac:name="anchor"><ac:default-parameter>fetch-install</ac:default-parameter></ac:macro></p>
<h2>Module Fetch+Install</h2>
<p>Most typically, people will not want to fetch and install modules in two separate commands. We could provide a simple wrapper that would trigger both:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf module install FooModule]]></ac:plain-text-body></ac:macro>

<p>This would first fetch, then install the module (if required).</p>

<p><ac:macro ac:name="anchor"><ac:default-parameter>remove-downgrade</ac:default-parameter></ac:macro></p>
<h2>Module Removal and Downgrades</h2>
<p>If a module is not "installable" then a simple directory removal would be sufficient. In all other cases there should be a MyModule\Module::remove($keepConfig) method that, if the user wishes, can keep the configuration present. The install() method would have to check for existing configuration and be sure merge or skip replacing the configuration files should the user decide to install the module again. (Added via <ac:link><ri:user ri:username="spiffyjr" /></ac:link>'s comment.)</p>

<p><ac:macro ac:name="anchor"><ac:default-parameter>other-considerations</ac:default-parameter></ac:macro></p>
<h2>Other Considerations</h2>
<p>If the user is already cd'd into a module's directory, commands like `zf module upgrade` could be ran without the name or path to the module.</p>

<p><ac:macro ac:name="anchor"><ac:default-parameter>community-pyrus-channel</ac:default-parameter></ac:macro></p>
<h2>Community Pyrus Channel</h2>
<p>It is proposed that we have an "official" Zend Framework module Pyrus channel. This channel should be the default configured channel that is searched when `zf install FooModule` is ran. Additionally, there should be a way to easily publish modules to this repository via the command line. This idea comes from node.js's NPM package manager:</p>

<h3>CLI Pyrus Channel Publishing</h3>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf channel register janedoe@domain.tld
Choose a password:
Confirm password:]]></ac:plain-text-body></ac:macro>

<p>This would utilize SSL by default. Upon successful registration, it would store the credentials in a config file somewhere.</p>

<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[prompt> zf channel publish ./modules/MyModule]]></ac:plain-text-body></ac:macro>

<p>Meta-data could be pulled from the Module class, with certain fields being required.</p>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Oct 22, 2011

    <p>Removals:</p>

    <p>If a module is not "installable" then a simple directory removal would be sufficient. In all other cases there should be a MyModule\Module::remove($keepConfig) method that, if the user wishes, can keep the configuration present. The install() method would have to check for existing configuration and be sure merge or skip replacing the configuration files should the user decide to install the module again.</p>

    1. Oct 23, 2011

      <p>I've added this inline to the RFC since it was lacking anything on this topic.</p>

  2. Oct 23, 2011

    <p>I think it would be useful to have a command that would list installed modules.</p>

    <p>zf module list<br />
    – FooModule - v1.2<br />
    – BarModule - v2.6</p>

    <p>Also I see you have upgrade but how are versions of modules handled, I am thinking about the usecase where you need to install v1 of a module instead of the latest one.</p>

    <p>How are errors handled during installation? It would be great (not sure if possible) that errors would be caught and changes not made to the project, some sort of atomic operation. Maybe we could also have:</p>

    <p>prompt> zf module test git://github.com/JaneDoe/FooModule.git</p>

    <p>So this would run unit tests as well as testing for any install problems.</p>

    <p>Thats my 2cents, like the look of how the modules are progressing.</p>

    1. Oct 23, 2011

      <p>I like the idea of `zf module list`, though I'm wondering which directories it would scan, or if we'd keep application-specific and/or system-wide installation manifests or some sort (I'll have to look at how Pyrus handles this as an example maybe).</p>

      <p>`zf module test` is also a great idea.. I think maybe checking for install problems could be done with `zf module install git://github.com/JaneDoe/FooModule.git --dry-run`, then `zf module test` could be used for unit tests. Though, to be able to run unit tests in a uniform way like this, we'll need one of two things: either all unit tests will always have to be found in the same spot, or we'll have to add a method to the Module class so that modules can tell ZF where to find unit test. I think we could have a default we check for "FooModule/tests" then a method to allow specifying alternative locations.</p>

      <p>Thanks for the feedback!</p>

  3. Oct 23, 2011

    <p>I don't like <strong>fetch</strong> as keyword. It's more natural to have <strong>zf install module</strong>.<br />
    With Tool component, you have this syntax: <strong>zf <action> <resource></strong> instead of <em>zf <resource> <action></em>.</p>

    <p>I prefer <strong>update</strong> than <em>upgrade</em>.</p>

    <p>In root application directory, we should only have <strong>zf install module</strong> (like gems).</p>

    <p>Can we choose version of module?<br />
    Can we configure channels with alias?</p>

    <p>I think we should have <strong>zf create module</strong> too (to help with new module).</p>

    <p><strong>init</strong> in others tools (git, bundler, etc) is not to run <em>deploy</em> scripts. This can mislead the user IMHO.</p>

    <p>@Keith Pope: +1 for list</p>

    1. Oct 23, 2011

      <p>Okay, so adding the fetch commands was mostly to illustrate the difference that there's two actions going on, and that sometimes the second one is optional for simple modules with no install actions. I think we could leave it, as sometimes a user may want to download the module from the distribution source into maybe a system-wide modules directory, but not run any installation actions yet.</p>

      <p>Could we alias both upgrade and update and avoid that entire debate? Then it "just works" for the user no matter what they type. I know pear/pecl (and I assume pyrus) only supports one or the other (couldn't tell you which without looking) and I seem to always take two tries to get it right.</p>

      <p>I would like to be able to specify versions when installing modules, however keep in mind every distribution method may not be "version-friendly." For example, someone may publish a single latest release phar via http and not keep every version available like a Git repository might.</p>

      <p>If Pyrus supports channel aliases, sure. If not, we could probably add this as a wrapper pretty easy.</p>

      <p>+1 on the ability to create a module. For consistency, I might suggest `zf module create`... It doesn't read quite as smooth in English because the verb is last, but I think having all these verbs with 'module' commands is much more sloppy than a single 'module' command with multiple verbs.</p>

      <p>Also, I agree init is a bad name; we could probably come up with something more descriptive for this.</p>

  4. Oct 24, 2011

    <p>Just been thinking about the installation of modules and noticed this part of the RFC:</p>

    <p>"This process can always be done manually, and does not involve triggering any sort of installation methods on the module being fetched"</p>

    <p>Does this mean there is no installation of things like database tables? So the distribution contains just the module and configuration is manual.</p>

    1. Oct 25, 2011

      <p>Nope, not at all. I just meant to differentiate between "fetching" which is simply the act of getting the module code from wherever, and "installing" which is actually setting up db's, copying assets, etc.</p>

      1. Oct 25, 2011

        <p>Ok in that case I have another question <ac:emoticon ac:name="smile" /></p>

        <p>I was thinking that we could have an installable interface (I haven't looked at any of the current code btw), then I was thinking about how to handle errors...</p>

        <p>Could we have some way of rolling back on errors, something like rollback(RollBackContext $context), this would provide information about the error which the developer could use to rollback based on where the install got to.</p>

        <p>The reason I was thinking about this is that if we have errors that mean you end up with a half installed module you would then need to manually remove the module and its assets. I think this would mainly be on DB errors but there could be others.</p>

        <p>I do have one concern with this in that it could become overly complicated, but I thought I would put the idea out there anyway. </p>

  5. Apr 12, 2012

    <p>Due to a current setup I would also prefer a module that allows you to install and activate modules via a web-frontend when there is no shell-access to the webserver. </p>

    <p>For my purposes I've hacked together a <a href="https://github.com/heiglandreas/ModuleManager">ModuleManager-Module</a> (mainly symlinking the public-folder of a module), but perhaps that can be a starting point for a CLI-Version also? That would combine ModuleManagement into one single tool. </p>