We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 22303 MODX Staff
    • 10,725 Posts
    Ok, one of the final delays in getting 0.9.7 ready for preview is having at least the basic add-ons that have been included in our core distributions to-date, migrated to the new API’s and packaged for distribution as official MODx transport packages. It’s now time for component developers to step-up to help migrate and package their components for 0.9.7.

    As part of this effort, I want to encourage a little more formality in maintaining the components considered critical to the project. To get us started, I have created a new SVN repository (see http://svn.modxcms.com:8000/svn/modx-components) that contains a directory for each component that is to be packaged individually, and within each of those is the standard branches/tags/trunk structure. But the structure in trunk is equally as important, especially the _build/ directory and the structure for the rest of the component source, which I will try to explain, as they relate to the build scripts; here’s an example:
    <?php
    $mtime = microtime();
    $mtime = explode(" ", $mtime);
    $mtime = $mtime[1] + $mtime[0];
    $tstart = $mtime;
    
    // get rid of time limit
    set_time_limit(0);
    
    // create this file and override with your own defines here (see build.config.sample.php)
    require_once ('build.config.php');
    
    require_once (MODX_CORE_PATH . 'model/modx/modx.class.php');
    $modx= new modX();
    $modx->initialize('mgr');
    //$modx->setDebug(true);
    $modx->loadClass('transport.xPDOTransport', XPDO_CORE_PATH, true, true);
    if (!$workspace= $modx->getObject('modWorkspace', array('active' => 1))) {
        echo "\nYou must have a valid core installation with an active workspace to run the build.\n";
        exit();
    }
    $packageDirectory= $workspace->get('path') . 'packages/';
    $packageSignature= array (
        'name' => 'tinymce',
        'version' => '2.0.9',
        'release' => 'rc2',
    );
    $signature= implode('-', $packageSignature);
    $packageFilename= $signature . '.transport.zip';
    if (file_exists($packageDirectory . $packageFilename)) {
        unlink($packageDirectory . $packageFilename);
    }
    if (file_exists($packageDirectory . $signature) && is_dir($packageDirectory . $signature)) {
        $cacheManager= $modx->getCacheManager();
        $cacheManager->deleteTree($packageDirectory . $signature);
    }
    $package= new xPDOTransport($modx, $signature, $packageDirectory);
    $sources= array (
        'assets' => dirname(dirname(__FILE__)) . '/assets/'
    );
    
    // get the source from the actual snippet in your database (make sure it is correct in db)
    // [alternative] you could also manually create the object, grabbing the source from a file
    // or you can manually set the properties of the object before putting it in the package
    $c= $modx->getObject('modPlugin', array ('name' => 'TinyMCE'));
    $c->set('category', 0);
    
    // use resolve attributes of type 'php' to add scripts that run after the object record is
    // saved to the appropriate database table when the package is installed
    $attributes['resolve'][]= array (
        'type' => 'php',
        'source' => dirname(__FILE__) . '/scripts/add_plugin_events.php',
    );
    
    // use resolve attributes of type 'file' to add physical file resources to the file system
    // when the package is installed; target is evaluated on the deployment it is being
    // installed at, so no matter where users have configured the location of various
    // directories, you can install the files in the appropriate place
    $attributes['resolve'][]= array (
        'type' => 'file',
        'source' => $sources['assets'] . 'plugins/tinymce',
        'target' => "return MODX_ASSETS_PATH . 'plugins/';",
    );
    
    // this package attribute indicates that the name field must be unique on install
    $attributes['unique_key']= 'name';
    
    // this puts the object into the package
    $package->put($c, $attributes);
    
    // this compresses the package into a zip file
    $package->pack();
    
    $mtime= microtime();
    $mtime= explode(" ", $mtime);
    $mtime= $mtime[1] + $mtime[0];
    $tend= $mtime;
    $totalTime= ($tend - $tstart);
    $totalTime= sprintf("%2.4f s", $totalTime);
    
    echo "\nExecution time: {$totalTime}\n";
    
    exit ();
    ?>

    Now you can simply run this script to build a package from your sources. The tricky part of course will be testing the components within a deployment, but I have yet to find a simple way to manage this. I imagine as more people get involved and start building packages, we’ll find better solutions to this. But for now you’ll just have to make sure you copy changes to your file dependencies when developing/testing in a deployment back to the appropriate source locations in the component’s SVN repository for check-in and package building.

    This is more work than most of you are used to when developing a component, but I think the benefits of packaging and consistency in development structure will help strengthen the incentives for more serious development of MODx add-ons and extensions.

    I am in the process of setting up a temporary download repository where packages can be retrieved, as well as the infrastructure for providing trusted downloads of the packages via web services, directly to a MODx deployment. These services will be deployed in conjunction with a new, refactored version of the MODx add-on repository. More on this soon, but until this is ready, we can simply communicate when new components are ready to be posted and I’ll build the packages and place them in the download area.

    Please don’t hesitate to ask questions or make suggestions if you have them.

    NOTE: You must upgrade to the latest SVN version of 0.9.7 for these new build scripts to work, as they require the presence of a new core class called modWorkspace (table = workspaces), and two additional classes called transport.modTransportPackage and transport.modTransportProvider in order to actually perform installations from the packages you build.
      • 25663 MODX Staff
      • 12,272 Posts
      Jason, from a high-level general overview perspective, can you describe the general process of installing packages (and creating them) for everyone ... maybe even what the core files that are involved do and what parts should be typically modified? Thanks!
        Ryan Thrash, MODX Co-Founder
        Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
        • 22303 MODX Staff
        • 10,725 Posts
        Quote from: rthrash at Oct 24, 2007, 11:02 AM

        Jason, from a high-level general overview perspective, can you describe the general process of installing packages (and creating them) for everyone ... maybe even what the core files that are involved do and what parts should be typically modified? Thanks!
        shaun is going to do us one better, and create a class to abstract the build scripts, creating an easy to use API with accompanying documentation. This will make it easier to understand and develop scripts to create these packages.

        For information on installing packages, see MODx Workspace Management and Transport Package Installation. More coming this afternoon.
          • 22303 MODX Staff
          • 10,725 Posts
          Also, I want to mention the purpose of the currently empty vendor/ path in the new modx-components SVN repository. Please read the following page from the SVN documentation regarding vendor branches. The idea is we import a vendor drop into our local repository from a specific version of a third-party add-on (e.g. tinymce) we’re going to use in one of our component projects. Then, you make a copy of this inside the appropriate location in your component project and make any customizations to the vendor code in this copy. This ensures we have a full history of the changes we make to a vendor product when we utilize them.
            • 28215
            • 4,149 Posts
            Ok, try this instead:

            <?php
            // get rid of time limit
            set_time_limit(0);
            
            // override with your own defines here (see build.config.sample.php)
            require_once ('build.config.php');
            
            require_once (MODX_CORE_PATH . 'model/modx/modx.class.php');
            $modx= new modX();
            $modx->initialize('mgr');
            //$modx->setDebug(true);
            
            
            $modx->loadClass('transport.modPackageBuilder','',false, true);
            $builder = new modPackageBuilder($modx);
            $builder->create('tinymce','2.0.9','rc2');
            
            $sources= array (
                'assets' => dirname(dirname(__FILE__)) . '/assets/'
            );
            
            // get the source from the actual snippet in your database
            // [alternative] you could also manually create the object, grabbing the source from a file
            $c= $modx->getObject('modPlugin', array ('name' => 'TinyMCE'));
            $c->set('category', 0);
            $vehicle = $builder->createVehicle($c);
            $vehicle->resolve('php',array(
            	'source' => dirname(__FILE__) . '/scripts/add_plugin_events.php',
            ));
            $vehicle->resolve('file',array(
                'source' => $sources['assets'] . 'plugins/tinymce',
                'target' => "return MODX_ASSETS_PATH . 'plugins/';",
            ));
            $vehicle->setUniqueKey('name');
            $builder->putVehicle($vehicle);
            $builder->pack();
            ?>
            
              shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com