diff --git a/Batali b/Batali index 1e3e6b1..adcf97e 100644 --- a/Batali +++ b/Batali @@ -6,36 +6,37 @@ Batali.define do cookbook 'mediawiki', git: 'https://github.com/67P/mediawiki-cookbook.git', ref: 'nginx' - cookbook 'php-fpm', - git: 'https://github.com/67P/cookbook-php-fpm.git', - ref: 'ubuntu_systemd' cookbook 'wordpress', git: 'https://github.com/67P/wordpress-cookbook.git', ref: 'relax_dependencies' - cookbook 'postfix' - cookbook 'unattended-upgrades' - cookbook 'poise-ruby-build', '~> 1.1.0' - cookbook 'application', '~> 5.2.0' - cookbook 'application_javascript' - cookbook 'application_ruby', '~> 4.1.0' - cookbook 'application_git', '~> 1.1.0' # 1.2.0 doesn't work with knife-solo - cookbook 'users', '~> 5.0.0' - cookbook 'sudo', '~> 3.5.0' - cookbook 'hostname' cookbook 'redis', git: 'https://github.com/phlipper/chef-redis.git', ref: 'v0.5.6' - cookbook 'firewall', '~> 2.6.1' - cookbook 'chef_nginx', '~> 6.0.2' - cookbook 'build-essential' - cookbook 'mysql' - cookbook 'postgresql', '~> 6.1' + cookbook 'postfix', '~> 5.0.2' + cookbook 'php-fpm', '~> 0.7.9' + cookbook 'php', '~> 4.2.0' + cookbook 'poise-ruby-build', '~> 1.1.0' + cookbook 'application', '~> 5.2.0' + cookbook 'application_javascript', '~> 1.0.0' + cookbook 'application_ruby', '~> 4.1.0' + cookbook 'application_git', '~> 1.1.0' # 1.2.0 doesn't work with knife-solo + cookbook 'users', '~> 5.0.0' + cookbook 'sudo', '~> 3.5.0' + cookbook 'hostname', '~> 0.4.2' + cookbook 'firewall', '~> 2.6.2' + cookbook 'chef_nginx', '~> 6.1.1' + cookbook 'build-essential', '~> 8.0.3' + cookbook 'mysql', '~> 8.4.0' + cookbook 'postgresql', '~> 6.1.1' + # Deprecated, but wordpress and mediawiki depend on it and it would painful + # to change it without moving the databases cookbook 'database' - cookbook 'mysql2_chef_gem' - cookbook 'chef_client_updater', '~> 1.0.2' - cookbook 'timezone-ii' - cookbook 'nodejs', '~> 3.0.0' - cookbook 'ark', '~> 3.0.0' - cookbook 'logrotate', '~> 2.1.0' - cookbook 'openssl', '~> 7.0.1' + cookbook 'mysql2_chef_gem', '~> 2.0.1' + cookbook 'chef_client_updater', '~> 1.1.1' + cookbook 'timezone-ii', '~> 0.2.0' + cookbook 'nodejs', '~> 3.0.0' + cookbook 'ark', '~> 3.1.0' + cookbook 'logrotate', '~> 2.2.0' + cookbook 'openssl', '~> 7.1.0' + cookbook 'ntp', '~> 3.4.0' end diff --git a/Vagrantfile b/Vagrantfile index a5221b6..cb1c22a 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -12,8 +12,7 @@ Vagrant.configure(2) do |config| # Every Vagrant development environment requires a box. You can search for # boxes at https://atlas.hashicorp.com/search. - config.vm.box = "bento/ubuntu-15.04" - + config.vm.box = "bento/ubuntu-16.04" config.vm.provider :virtualbox do |vb| # Customize the amount of memory on the VM: @@ -98,12 +97,12 @@ Vagrant.configure(2) do |config| chef.environments_path = 'environments' chef.encrypted_data_bag_secret_key_path = '.chef/encrypted_data_bag_secret' chef.environment = 'development' - # chef.add_recipe 'kosmos-wordpress' + chef.add_recipe 'kosmos-base' + chef.add_recipe 'kosmos-wordpress' # chef.add_recipe 'sockethub' - chef.add_recipe 'kosmos-mastodon' - chef.add_recipe 'kosmos-mastodon::nginx' + # chef.add_recipe 'kosmos-mastodon' + # chef.add_recipe 'kosmos-mastodon::nginx' # chef.add_recipe '5apps-hubot::xmpp_botka' # chef.add_recipe 'kosmos-hubot' - end end diff --git a/batali.manifest b/batali.manifest index 1e5e03f..7619dc9 100644 --- a/batali.manifest +++ b/batali.manifest @@ -71,21 +71,13 @@ [ "yum-epel", ">= 0.0.0" - ], - [ - "windows", - ">= 0.0.0" - ], - [ - "iis", - ">= 0.0.0" ] ], - "version": "1.7.2", + "version": "4.2.0", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/php/versions/1.7.2/download", - "version": "1.7.2" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/php/versions/4.2.0/download", + "version": "4.2.0" } }, { @@ -100,11 +92,11 @@ ">= 1.1" ] ], - "version": "8.0.1", + "version": "8.0.3", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/build-essential/versions/8.0.1/download", - "version": "8.0.1" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/build-essential/versions/8.0.3/download", + "version": "8.0.3" } }, { @@ -198,35 +190,28 @@ { "name": "mysql", "dependencies": [ - [ - "yum-mysql-community", - ">= 0.0.0" - ], - [ - "smf", - ">= 0.0.0" - ] + ], - "version": "6.1.3", + "version": "8.4.0", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql/versions/6.1.3/download", - "version": "6.1.3" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql/versions/8.4.0/download", + "version": "8.4.0" } }, { - "name": "yum-mysql-community", + "name": "yum-epel", "dependencies": [ [ "yum", - ">= 3.2" + "~> 3.0" ] ], - "version": "0.1.21", + "version": "0.3.6", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum-mysql-community/versions/0.1.21/download", - "version": "0.1.21" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum-epel/versions/0.3.6/download", + "version": "0.3.6" } }, { @@ -234,80 +219,11 @@ "dependencies": [ ], - "version": "5.0.0", + "version": "3.13.0", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum/versions/5.0.0/download", - "version": "5.0.0" - } - }, - { - "name": "smf", - "dependencies": [ - [ - "rbac", - ">= 1.0.1" - ] - ], - "version": "2.2.8", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/smf/versions/2.2.8/download", - "version": "2.2.8" - } - }, - { - "name": "rbac", - "dependencies": [ - - ], - "version": "1.0.3", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/rbac/versions/1.0.3/download", - "version": "1.0.3" - } - }, - { - "name": "yum-epel", - "dependencies": [ - [ - "compat_resource", - ">= 12.16.3" - ] - ], - "version": "2.1.1", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum-epel/versions/2.1.1/download", - "version": "2.1.1" - } - }, - { - "name": "compat_resource", - "dependencies": [ - - ], - "version": "12.16.3", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/compat_resource/versions/12.16.3/download", - "version": "12.16.3" - } - }, - { - "name": "iis", - "dependencies": [ - [ - "windows", - ">= 1.34.6" - ] - ], - "version": "5.0.8", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/iis/versions/5.0.8/download", - "version": "5.0.8" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum/versions/3.13.0/download", + "version": "3.13.0" } }, { @@ -349,15 +265,15 @@ } }, { - "name": "openssl", + "name": "compat_resource", "dependencies": [ ], - "version": "7.0.1", + "version": "12.19.0", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/openssl/versions/7.0.1/download", - "version": "7.0.1" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/compat_resource/versions/12.19.0/download", + "version": "12.19.0" } }, { @@ -384,11 +300,11 @@ ">= 0.0.0" ] ], - "version": "6.0.2", + "version": "6.1.1", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/chef_nginx/versions/6.0.2/download", - "version": "6.0.2" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/chef_nginx/versions/6.1.1/download", + "version": "6.1.1" } }, { @@ -420,22 +336,22 @@ "dependencies": [ [ "build-essential", - ">= 0.0.0" + ">= 2.4.0" ], [ "mysql", - "~> 6.0" + ">= 8.2.0" ], [ "mariadb", ">= 0.0.0" ] ], - "version": "1.0.2", + "version": "2.0.1", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql2_chef_gem/versions/1.0.2/download", - "version": "1.0.2" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql2_chef_gem/versions/2.0.1/download", + "version": "2.0.1" } }, { @@ -478,19 +394,18 @@ "dependencies": [ [ "apt", - "> 0" + ">= 0.0.0" ], [ "yum", ">= 3.0" ] ], - "version": "0.7.5", + "version": "0.7.9", "source": { - "url": "https://github.com/67P/cookbook-php-fpm.git", - "ref": "00ae43a225cf23fd3ed937f27ab25aba8d812db9", - "type": "Batali::Source::Git", - "subdirectory": null + "type": "Batali::Source::Site", + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/php-fpm/versions/0.7.9/download", + "version": "0.7.9" } }, { @@ -553,6 +468,21 @@ "subdirectory": null } }, + { + "name": "iis", + "dependencies": [ + [ + "windows", + ">= 1.34.6" + ] + ], + "version": "5.0.8", + "source": { + "type": "Batali::Source::Site", + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/iis/versions/5.0.8/download", + "version": "5.0.8" + } + }, { "name": "tar", "dependencies": [ @@ -577,31 +507,32 @@ "version": "0.9.0" } }, + { + "name": "redis", + "dependencies": [ + [ + "apt", + "> 0" + ] + ], + "version": "0.5.6", + "source": { + "url": "https://github.com/phlipper/chef-redis.git", + "ref": "7476279fc9c8727f082b8d77b5e1922dc2ef437b", + "type": "Batali::Source::Git", + "subdirectory": null + } + }, { "name": "postfix", "dependencies": [ ], - "version": "5.0.1", + "version": "5.0.2", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/postfix/versions/5.0.1/download", - "version": "5.0.1" - } - }, - { - "name": "unattended-upgrades", - "dependencies": [ - [ - "apt", - ">= 0.0.0" - ] - ], - "version": "0.1.2", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/unattended-upgrades/versions/0.1.2/download", - "version": "0.1.2" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/postfix/versions/5.0.2/download", + "version": "5.0.2" } }, { @@ -927,11 +858,11 @@ ">= 0.0.0" ] ], - "version": "0.4.0", + "version": "0.4.2", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/hostname/versions/0.4.0/download", - "version": "0.4.0" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/hostname/versions/0.4.2/download", + "version": "0.4.2" } }, { @@ -946,22 +877,6 @@ "version": "2.4.5" } }, - { - "name": "redis", - "dependencies": [ - [ - "apt", - "> 0" - ] - ], - "version": "0.5.6", - "source": { - "url": "https://github.com/phlipper/chef-redis.git", - "ref": "7476279fc9c8727f082b8d77b5e1922dc2ef437b", - "type": "Batali::Source::Git", - "subdirectory": null - } - }, { "name": "firewall", "dependencies": [ @@ -970,11 +885,11 @@ ">= 0.0.0" ] ], - "version": "2.6.1", + "version": "2.6.2", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/firewall/versions/2.6.1/download", - "version": "2.6.1" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/firewall/versions/2.6.2/download", + "version": "2.6.2" } }, { @@ -985,11 +900,11 @@ ">= 12.16.3" ] ], - "version": "1.0.2", + "version": "1.1.1", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/chef_client_updater/versions/1.0.2/download", - "version": "1.0.2" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/chef_client_updater/versions/1.1.1/download", + "version": "1.1.1" } }, { @@ -1035,6 +950,18 @@ "version": "3.0.0" } }, + { + "name": "homebrew", + "dependencies": [ + + ], + "version": "3.0.0", + "source": { + "type": "Batali::Source::Site", + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/homebrew/versions/3.0.0/download", + "version": "3.0.0" + } + }, { "name": "ark", "dependencies": [ @@ -1051,38 +978,47 @@ ">= 0.0.0" ] ], - "version": "3.0.0", + "version": "3.1.0", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/ark/versions/3.0.0/download", - "version": "3.0.0" - } - }, - { - "name": "homebrew", - "dependencies": [ - - ], - "version": "3.0.0", - "source": { - "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/homebrew/versions/3.0.0/download", - "version": "3.0.0" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/ark/versions/3.1.0/download", + "version": "3.1.0" } }, { "name": "logrotate", "dependencies": [ - [ - "compat_resource", - ">= 0.0.0" - ] + ], - "version": "2.1.0", + "version": "2.2.0", "source": { "type": "Batali::Source::Site", - "url": "https://supermarket.chef.io:443/api/v1/cookbooks/logrotate/versions/2.1.0/download", - "version": "2.1.0" + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/logrotate/versions/2.2.0/download", + "version": "2.2.0" + } + }, + { + "name": "openssl", + "dependencies": [ + + ], + "version": "7.1.0", + "source": { + "type": "Batali::Source::Site", + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/openssl/versions/7.1.0/download", + "version": "7.1.0" + } + }, + { + "name": "ntp", + "dependencies": [ + + ], + "version": "3.4.0", + "source": { + "type": "Batali::Source::Site", + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/ntp/versions/3.4.0/download", + "version": "3.4.0" } } ] diff --git a/cookbooks/ark/CHANGELOG.md b/cookbooks/ark/CHANGELOG.md index f10ff09..0639bc9 100644 --- a/cookbooks/ark/CHANGELOG.md +++ b/cookbooks/ark/CHANGELOG.md @@ -2,7 +2,13 @@ This file is used to list changes made in each version of the ark cookbook. +## 3.1.0 (2017-05-06) + +- Ensure the dependencies get installed on Chef 13 Amazon Linux systems +- Require Chef 12.7+ and remove action_class.class_eval usage + ## 3.0.0 (2017-04-05) + - Rewrite of resource to custom resources. - Remove EOL platforms from testing. - Update zlib URL diff --git a/cookbooks/ark/README.md b/cookbooks/ark/README.md index 5b05216..42f7cb6 100644 --- a/cookbooks/ark/README.md +++ b/cookbooks/ark/README.md @@ -44,7 +44,7 @@ Should work on common Unix/Linux systems with typical userland utilities like ta ### Chef -- Chef 12.5+ +- Chef 12.7+ ### Cookbooks diff --git a/cookbooks/ark/attributes/default.rb b/cookbooks/ark/attributes/default.rb index 0767723..10b3e01 100644 --- a/cookbooks/ark/attributes/default.rb +++ b/cookbooks/ark/attributes/default.rb @@ -30,10 +30,10 @@ default['ark']['sevenzip_binary'] = nil pkgs = %w(libtool autoconf) unless platform_family?('mac_os_x') pkgs += %w(make) unless platform_family?('mac_os_x', 'freebsd') pkgs += %w(unzip rsync gcc) unless platform_family?('mac_os_x') -pkgs += %w(autogen) unless platform_family?('rhel', 'fedora', 'mac_os_x', 'suse') +pkgs += %w(autogen) unless platform_family?('rhel', 'fedora', 'mac_os_x', 'suse', 'amazon') pkgs += %w(gtar) if platform?('freebsd') || platform?('smartos') pkgs += %w(gmake) if platform?('freebsd') -if platform_family?('rhel', 'suse') +if platform_family?('rhel', 'suse', 'amazon') if node['platform_version'].to_i >= 7 pkgs += %w(xz bzip2 tar) elsif node['platform_version'].to_i < 7 diff --git a/cookbooks/ark/metadata.json b/cookbooks/ark/metadata.json index 7746bfc..a531332 100644 --- a/cookbooks/ark/metadata.json +++ b/cookbooks/ark/metadata.json @@ -1 +1 @@ -{"name":"ark","version":"3.0.0","description":"Provides a custom resource for installing runtime artifacts in a predictable fashion","long_description":"# ark cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/ark.svg?branch=master)](https://travis-ci.org/chef-cookbooks/ark) [![Cookbook Version](https://img.shields.io/cookbook/v/ark.svg)](https://supermarket.chef.io/cookbooks/ark)\n\n## Overview\n\nThis cookbook provides `ark`, a resource for managing software archives. It manages the fetch-unpack-configure-build-install process common to installing software from source, or from binary distributions that are not fully fledged OS packages.\n\nThis cookbook started its life as a modified version of Infochimp's install_from cookbook. It has since been heavily refactored and extended to meet different use cases.\n\nGiven a simple project archive available at a url:\n\n```ruby\nark 'pig' do\n url 'http://apache.org/pig/pig-0.8.0.tar.gz'\nend\n```\n\nThe `ark` resource will:\n\n- fetch it to to `/var/cache/chef/`\n- unpack it to the default path (`/usr/local/pig-0.8.0`)\n- create a symlink for `:home_dir` (`/usr/local/pig`) pointing to path\n- add specified binary commands to the environment `PATH` variable\n\nBy default, the ark will not run again if the `:path` is not empty. Ark provides many actions to accommodate different use cases, such as `:dump`, `:cherry_pick`, `:put`, and `:install_with_make`.\n\nAt this time ark only handles files available from URLs using the [remote_file](http://docs.chef.io/resource_remote_file.html) provider. It does handle local files using the `file://` protocol.\n\n## Requirements\n\n### Platforms\n\n- Debian/Ubuntu\n- RHEL/CentOS/Scientific/Oracle\n- Fedora\n- FreeBSD\n- SmartOS\n- Mac OS X\n- openSUSE / SUSE Linux Enterprises\n- Windows\n\nShould work on common Unix/Linux systems with typical userland utilities like tar, gzip, etc. May require the installation of build tools for compiling from source, but that installation is outside the scope of this cookbook.\n\n### Chef\n\n- Chef 12.5+\n\n### Cookbooks\n\n- build-essential\n- seven_zip\n- windows\n\n## Attributes\n\nCustomize the attributes to suit site specific conventions and defaults.\n\n- `node['ark']['apache_mirror']` - if the URL is an apache mirror, use the attribute as the default. default: `http://apache.mirrors.tds.net`\n- `node['ark']['prefix_root']` - default base location if the `prefix_root` is not passed into the resource. default: `/usr/local`\n- `node['ark']['prefix_bin']` - default binary location if the `prefix_bin` is not passed into the resource. default: `/usr/local/bin`\n- `node['ark']['prefix_home']` - default home location if the `prefix_home` is not passed into the resource. default: `/usr/local`\n- `node['ark']['package_dependencies']` - prerequisite system packages that need to be installed to support ark. default: varies based on platform\n- `node['ark']['tar']` - allows overriding the default path to the tar binary, which varies based on platform\n- `node['ark']['sevenzip_binary']` - allows overriding the default path to the 7zip binary, which is determined based on registry key value\n\n## Resources\n\n- `ark` - does the extract/build/configure \n\n### Actions\n\n- `:install`: extracts the file and creates a 'friendly' symbolic link to the extracted directory path\n- `:configure`: configure ahead of the install action\n- `:install_with_make`: extracts the archive to a path, runs `configure`, `make`, and `make install`.\n- `:dump`: strips all directories from the archive and dumps the contained files into a specified path\n- `:cherry_pick`: extract a specified file from an archive and places in specified path\n- `:put`: extract the archive to a specified path, does not create any symbolic links\n- `:remove`: removes the extracted directory and related symlink #TODO\n- `:setup_py`: runs the command \"python setup.py\" in the extracted directory\n- `:setup_py_build`: runs the command \"python setup.py build\" in the extracted directory\n- `:setup_py_install`: runs the command \"python setup.py install\" in the extracted directory\n\n### :cherry_pick\n\nExtract a specified file from an archive and places in specified path.\n\n#### Relevant Attribute Parameters for :cherry_pick\n\n- `path`: directory to place file in.\n- `creates`: specific file to cherry-pick.\n\n### :dump\n\nStrips all directories from the archive and dumps the contained files into a specified path.\n\nNOTE: This currently only works for zip archives\n\n#### Attribute Parameters for :dump\n\n- `path`: path to dump files to.\n- `mode`: file mode for `app_home`, as an integer.\n\n - Example: `0775`\n\n- `creates`: if you are appending files to a given directory, ark needs a condition to test whether the file has already been extracted. You can specify with creates, a file whose existence indicates the ark has previously been extracted and does not need to be extracted again.\n\n### :put\n\nExtract the archive to a specified path, does not create any symbolic links.\n\n#### Attribute Parameters for :put\n\n- `path`: path to extract to.\n\n - Default: `/usr/local`\n\n- `append_env_path`: boolean, if true, append the `./bin` directory of the extracted directory to the global `PATH` variable for all users.\n\n### Attribute Parameters\n\n- `name`: name of the package, defaults to the resource name.\n- `url`: url for tarball, `.tar.gz`, `.bin` (oracle-specific), `.war`, and `.zip` currently supported. Also supports special syntax\n- `:name:version:apache_mirror:` that will auto-magically construct download url from the apache mirrors site.\n- `version`: software version, defaults to `1`.\n- `mode`: file mode for `app_home`, is an integer.\n- `prefix_root`: default `prefix_root`, for use with `:install*` actions.\n- `prefix_home`: default directory prefix for a friendly symlink to the path.\n\n - Example: `/usr/local/maven` -> `/usr/local/maven-2.2.1`\n\n- `prefix_bin`: default directory to place a symlink to a binary command.\n\n - Example: `/opt/bin/mvn` -> `/opt/maven-2.2.1/bin/mvn`, where the `prefix_bin` is `/opt/bin`\n\n- `path`: path to extract the ark to. The `:install*` actions overwrite any user-provided values for `:path`.\n\n - Default: `/usr/local/-` for the `:install`, `:install_with_make` actions\n\n- `home_dir`: symbolic link to the path `:prefix_root/:name-:version`, does not apply to `:dump`, `:put`, or `:cherry_pick` actions.\n\n - Default: `:prefix_root/:name`\n\n- `has_binaries`: array of binary commands to symlink into `/usr/local/bin/`, you must specify the relative path.\n\n - Example: `[ 'bin/java', 'bin/javaws' ]`\n\n- `append_env_path`: boolean, similar to `has_binaries` but less granular. If true, append the `./bin` directory of the extracted directory to. the `PATH` environment variable for all users, by placing a file in `/etc/profile.d/`. The commands are symbolically linked into `/usr/bin/*`. This option provides more granularity than the boolean option.\n\n - Example: `mvn`, `java`, `javac`, etc.\n\n- `environment`: hash of environment variables to pass to invoked shell commands like `tar`, `unzip`, `configure`, and `make`.\n\n- `strip_components`: number of components in path to strip when extracting archive. With default value of `1`, ark strips the leading directory from an archive, which is the default for both `unzip` and `tar` commands.\n\n- `autoconf_opts`: an array of command line options for use with the GNU `autoconf` script.\n\n - Example: `[ '--include=/opt/local/include', '--force' ]`\n\n- `make_opts`: an array of command line options for use with `make`.\n\n - Example: `[ '--warn-undefined-variables', '--load-average=2' ]`\n\n- `owner`: owner of extracted directory.\n\n - Default: `root`\n\n- `group`: group of extracted directory.\n\n - Default: `root`\n\n- `backup`: The number of backups to be kept in /var/chef/backup (for UNIX- and Linux-based platforms) or C:/chef/backup (for the Microsoft Windows platform). Set to false to prevent backups from being kept.\n\n - Default: `5`\n\n#### Examples\n\nThis example copies `ivy.tar.gz` to `/var/cache/chef/ivy-2.2.0.tar.gz`, unpacks its contents to `/usr/local/ivy-2.2.0/` -- stripping the leading directory, and symlinks `/usr/local/ivy` to `/usr/local/ivy-2.2.0`\n\n```ruby\n # install Apache Ivy dependency resolution tool\n ark \"ivy\" do\n url 'http://someurl.example.com/ivy.tar.gz'\n version '2.2.0'\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n action :install\n end\n```\n\nThis example copies `jdk-7u2-linux-x64.tar.gz` to `/var/cache/chef/jdk-7.2.tar.gz`, unpacks its contents to `/usr/local/jvm/jdk-7.2/` -- stripping the leading directory, symlinks `/usr/local/jvm/default` to `/usr/local/jvm/jdk-7.2`, and adds `/usr/local/jvm/jdk-7.2/bin/` to the global `PATH` for all users. The user 'foobar' is the owner of the `/usr/local/jvm/jdk-7.2` directory:\n\n```ruby\n ark 'jdk' do\n url 'http://download.example.com/jdk-7u2-linux-x64.tar.gz'\n version '7.2'\n path \"/usr/local/jvm/\"\n home_dir \"/usr/local/jvm/default\"\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n append_env_path true\n owner 'foobar'\n end\n```\n\nInstall Apache Ivy dependency resolution tool in `/resource_name` in this case `/usr/local/ivy`, do not symlink, and strip any leading directory if one exists in the tarball:\n\n```ruby\n ark \"ivy\" do\n url 'http://someurl.example.com/ivy.tar.gz'\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n action :put\n end\n```\n\nInstall Apache Ivy dependency resolution tool in `/home/foobar/ivy`, strip any leading directory if one exists, don't keep backup copies of `ivy.tar.gz`:\n\n```ruby\n ark \"ivy\" do\n path \"/home/foobar\"\n url 'http://someurl.example.com/ivy.tar.gz'\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n action :put\n backup false\n end\n```\n\nStrip all directories and dump files into path specified by the path attribute. You must specify the `creates` attribute in order to keep the extraction from running every time. The directory path will be created if it doesn't already exist:\n\n```ruby\n ark \"my_jars\" do\n url \"http://example.com/bunch_of_jars.zip\"\n path \"/usr/local/tomcat/lib\"\n creates \"mysql.jar\"\n owner \"tomcat\"\n action :dump\n end\n```\n\nExtract specific files from a tarball (currently only handles one named file):\n\n```ruby\n ark 'mysql-connector-java' do\n url 'http://oracle.com/mysql-connector.zip'\n creates 'mysql-connector-java-5.0.8-bin.jar'\n path '/usr/local/tomcat/lib'\n action :cherry_pick\n end\n```\n\nBuild and install haproxy and use alternative values for `prefix_root`, `prefix_home`, and `prefix_bin`:\n\n```ruby\n ark \"haproxy\" do\n url \"http://haproxy.1wt.eu/download/1.5/src/snapshot/haproxy-ss-20120403.tar.gz\"\n version \"1.5\"\n checksum 'ba0424bf7d23b3a607ee24bbb855bb0ea347d7ffde0bec0cb12a89623cbaf911'\n make_opts [ 'TARGET=linux26' ]\n prefix_root '/opt'\n prefix_home '/opt'\n prefix_bin '/opt/bin'\n action :install_with_make\n end\n```\n\nYou can also supply the file extension in case the file extension can not be determined by the URL:\n\n```ruby\n ark \"test_autogen\" do\n url 'https://github.com/zeromq/libzmq/tarball/master'\n extension \"tar.gz\"\n action :install_with_make\n end\n```\n\n## License & Authors\n\n- Author: Philip (flip) Kromer - Infochimps, Inc([coders@infochimps.com](mailto:coders@infochimps.com))\n- Author: Bryan W. Berry ([bryan.berry@gmail.com](mailto:bryan.berry@gmail.com))\n- Author: Denis Barishev ([denis.barishev@gmail.com](mailto:denis.barishev@gmail.com))\n- Author: Sean OMeara ([someara@chef.io](mailto:someara@chef.io))\n- Author: John Bellone ([jbellone@bloomberg.net](mailto:jbellone@bloomberg.net))\n- Copyright: 2011, Philip (flip) Kromer - Infochimps, Inc\n- Copyright: 2012, Bryan W. Berry\n- Copyright: 2012, Denis Barishev\n- Copyright: 2013-2017, Chef Software, Inc\n- Copyright: 2014, Bloomberg L.P.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","suse":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0","amazon":">= 0.0.0","windows":">= 0.0.0","mac_os_x":">= 0.0.0","smartos":">= 0.0.0","freebsd":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","windows":">= 0.0.0","seven_zip":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"ark::default":"Installs packages needed by the custom resource"},"source_url":"https://github.com/chef-cookbooks/ark","issues_url":"https://github.com/chef-cookbooks/ark/issues","chef_version":">= 12.5","ohai_version":{}} \ No newline at end of file +{"name":"ark","version":"3.1.0","description":"Provides a custom resource for installing runtime artifacts in a predictable fashion","long_description":"# ark cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/ark.svg?branch=master)](https://travis-ci.org/chef-cookbooks/ark) [![Cookbook Version](https://img.shields.io/cookbook/v/ark.svg)](https://supermarket.chef.io/cookbooks/ark)\n\n## Overview\n\nThis cookbook provides `ark`, a resource for managing software archives. It manages the fetch-unpack-configure-build-install process common to installing software from source, or from binary distributions that are not fully fledged OS packages.\n\nThis cookbook started its life as a modified version of Infochimp's install_from cookbook. It has since been heavily refactored and extended to meet different use cases.\n\nGiven a simple project archive available at a url:\n\n```ruby\nark 'pig' do\n url 'http://apache.org/pig/pig-0.8.0.tar.gz'\nend\n```\n\nThe `ark` resource will:\n\n- fetch it to to `/var/cache/chef/`\n- unpack it to the default path (`/usr/local/pig-0.8.0`)\n- create a symlink for `:home_dir` (`/usr/local/pig`) pointing to path\n- add specified binary commands to the environment `PATH` variable\n\nBy default, the ark will not run again if the `:path` is not empty. Ark provides many actions to accommodate different use cases, such as `:dump`, `:cherry_pick`, `:put`, and `:install_with_make`.\n\nAt this time ark only handles files available from URLs using the [remote_file](http://docs.chef.io/resource_remote_file.html) provider. It does handle local files using the `file://` protocol.\n\n## Requirements\n\n### Platforms\n\n- Debian/Ubuntu\n- RHEL/CentOS/Scientific/Oracle\n- Fedora\n- FreeBSD\n- SmartOS\n- Mac OS X\n- openSUSE / SUSE Linux Enterprises\n- Windows\n\nShould work on common Unix/Linux systems with typical userland utilities like tar, gzip, etc. May require the installation of build tools for compiling from source, but that installation is outside the scope of this cookbook.\n\n### Chef\n\n- Chef 12.7+\n\n### Cookbooks\n\n- build-essential\n- seven_zip\n- windows\n\n## Attributes\n\nCustomize the attributes to suit site specific conventions and defaults.\n\n- `node['ark']['apache_mirror']` - if the URL is an apache mirror, use the attribute as the default. default: `http://apache.mirrors.tds.net`\n- `node['ark']['prefix_root']` - default base location if the `prefix_root` is not passed into the resource. default: `/usr/local`\n- `node['ark']['prefix_bin']` - default binary location if the `prefix_bin` is not passed into the resource. default: `/usr/local/bin`\n- `node['ark']['prefix_home']` - default home location if the `prefix_home` is not passed into the resource. default: `/usr/local`\n- `node['ark']['package_dependencies']` - prerequisite system packages that need to be installed to support ark. default: varies based on platform\n- `node['ark']['tar']` - allows overriding the default path to the tar binary, which varies based on platform\n- `node['ark']['sevenzip_binary']` - allows overriding the default path to the 7zip binary, which is determined based on registry key value\n\n## Resources\n\n- `ark` - does the extract/build/configure \n\n### Actions\n\n- `:install`: extracts the file and creates a 'friendly' symbolic link to the extracted directory path\n- `:configure`: configure ahead of the install action\n- `:install_with_make`: extracts the archive to a path, runs `configure`, `make`, and `make install`.\n- `:dump`: strips all directories from the archive and dumps the contained files into a specified path\n- `:cherry_pick`: extract a specified file from an archive and places in specified path\n- `:put`: extract the archive to a specified path, does not create any symbolic links\n- `:remove`: removes the extracted directory and related symlink #TODO\n- `:setup_py`: runs the command \"python setup.py\" in the extracted directory\n- `:setup_py_build`: runs the command \"python setup.py build\" in the extracted directory\n- `:setup_py_install`: runs the command \"python setup.py install\" in the extracted directory\n\n### :cherry_pick\n\nExtract a specified file from an archive and places in specified path.\n\n#### Relevant Attribute Parameters for :cherry_pick\n\n- `path`: directory to place file in.\n- `creates`: specific file to cherry-pick.\n\n### :dump\n\nStrips all directories from the archive and dumps the contained files into a specified path.\n\nNOTE: This currently only works for zip archives\n\n#### Attribute Parameters for :dump\n\n- `path`: path to dump files to.\n- `mode`: file mode for `app_home`, as an integer.\n\n - Example: `0775`\n\n- `creates`: if you are appending files to a given directory, ark needs a condition to test whether the file has already been extracted. You can specify with creates, a file whose existence indicates the ark has previously been extracted and does not need to be extracted again.\n\n### :put\n\nExtract the archive to a specified path, does not create any symbolic links.\n\n#### Attribute Parameters for :put\n\n- `path`: path to extract to.\n\n - Default: `/usr/local`\n\n- `append_env_path`: boolean, if true, append the `./bin` directory of the extracted directory to the global `PATH` variable for all users.\n\n### Attribute Parameters\n\n- `name`: name of the package, defaults to the resource name.\n- `url`: url for tarball, `.tar.gz`, `.bin` (oracle-specific), `.war`, and `.zip` currently supported. Also supports special syntax\n- `:name:version:apache_mirror:` that will auto-magically construct download url from the apache mirrors site.\n- `version`: software version, defaults to `1`.\n- `mode`: file mode for `app_home`, is an integer.\n- `prefix_root`: default `prefix_root`, for use with `:install*` actions.\n- `prefix_home`: default directory prefix for a friendly symlink to the path.\n\n - Example: `/usr/local/maven` -> `/usr/local/maven-2.2.1`\n\n- `prefix_bin`: default directory to place a symlink to a binary command.\n\n - Example: `/opt/bin/mvn` -> `/opt/maven-2.2.1/bin/mvn`, where the `prefix_bin` is `/opt/bin`\n\n- `path`: path to extract the ark to. The `:install*` actions overwrite any user-provided values for `:path`.\n\n - Default: `/usr/local/-` for the `:install`, `:install_with_make` actions\n\n- `home_dir`: symbolic link to the path `:prefix_root/:name-:version`, does not apply to `:dump`, `:put`, or `:cherry_pick` actions.\n\n - Default: `:prefix_root/:name`\n\n- `has_binaries`: array of binary commands to symlink into `/usr/local/bin/`, you must specify the relative path.\n\n - Example: `[ 'bin/java', 'bin/javaws' ]`\n\n- `append_env_path`: boolean, similar to `has_binaries` but less granular. If true, append the `./bin` directory of the extracted directory to. the `PATH` environment variable for all users, by placing a file in `/etc/profile.d/`. The commands are symbolically linked into `/usr/bin/*`. This option provides more granularity than the boolean option.\n\n - Example: `mvn`, `java`, `javac`, etc.\n\n- `environment`: hash of environment variables to pass to invoked shell commands like `tar`, `unzip`, `configure`, and `make`.\n\n- `strip_components`: number of components in path to strip when extracting archive. With default value of `1`, ark strips the leading directory from an archive, which is the default for both `unzip` and `tar` commands.\n\n- `autoconf_opts`: an array of command line options for use with the GNU `autoconf` script.\n\n - Example: `[ '--include=/opt/local/include', '--force' ]`\n\n- `make_opts`: an array of command line options for use with `make`.\n\n - Example: `[ '--warn-undefined-variables', '--load-average=2' ]`\n\n- `owner`: owner of extracted directory.\n\n - Default: `root`\n\n- `group`: group of extracted directory.\n\n - Default: `root`\n\n- `backup`: The number of backups to be kept in /var/chef/backup (for UNIX- and Linux-based platforms) or C:/chef/backup (for the Microsoft Windows platform). Set to false to prevent backups from being kept.\n\n - Default: `5`\n\n#### Examples\n\nThis example copies `ivy.tar.gz` to `/var/cache/chef/ivy-2.2.0.tar.gz`, unpacks its contents to `/usr/local/ivy-2.2.0/` -- stripping the leading directory, and symlinks `/usr/local/ivy` to `/usr/local/ivy-2.2.0`\n\n```ruby\n # install Apache Ivy dependency resolution tool\n ark \"ivy\" do\n url 'http://someurl.example.com/ivy.tar.gz'\n version '2.2.0'\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n action :install\n end\n```\n\nThis example copies `jdk-7u2-linux-x64.tar.gz` to `/var/cache/chef/jdk-7.2.tar.gz`, unpacks its contents to `/usr/local/jvm/jdk-7.2/` -- stripping the leading directory, symlinks `/usr/local/jvm/default` to `/usr/local/jvm/jdk-7.2`, and adds `/usr/local/jvm/jdk-7.2/bin/` to the global `PATH` for all users. The user 'foobar' is the owner of the `/usr/local/jvm/jdk-7.2` directory:\n\n```ruby\n ark 'jdk' do\n url 'http://download.example.com/jdk-7u2-linux-x64.tar.gz'\n version '7.2'\n path \"/usr/local/jvm/\"\n home_dir \"/usr/local/jvm/default\"\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n append_env_path true\n owner 'foobar'\n end\n```\n\nInstall Apache Ivy dependency resolution tool in `/resource_name` in this case `/usr/local/ivy`, do not symlink, and strip any leading directory if one exists in the tarball:\n\n```ruby\n ark \"ivy\" do\n url 'http://someurl.example.com/ivy.tar.gz'\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n action :put\n end\n```\n\nInstall Apache Ivy dependency resolution tool in `/home/foobar/ivy`, strip any leading directory if one exists, don't keep backup copies of `ivy.tar.gz`:\n\n```ruby\n ark \"ivy\" do\n path \"/home/foobar\"\n url 'http://someurl.example.com/ivy.tar.gz'\n checksum '89ba5fde0c596db388c3bbd265b63007a9cc3df3a8e6d79a46780c1a39408cb5'\n action :put\n backup false\n end\n```\n\nStrip all directories and dump files into path specified by the path attribute. You must specify the `creates` attribute in order to keep the extraction from running every time. The directory path will be created if it doesn't already exist:\n\n```ruby\n ark \"my_jars\" do\n url \"http://example.com/bunch_of_jars.zip\"\n path \"/usr/local/tomcat/lib\"\n creates \"mysql.jar\"\n owner \"tomcat\"\n action :dump\n end\n```\n\nExtract specific files from a tarball (currently only handles one named file):\n\n```ruby\n ark 'mysql-connector-java' do\n url 'http://oracle.com/mysql-connector.zip'\n creates 'mysql-connector-java-5.0.8-bin.jar'\n path '/usr/local/tomcat/lib'\n action :cherry_pick\n end\n```\n\nBuild and install haproxy and use alternative values for `prefix_root`, `prefix_home`, and `prefix_bin`:\n\n```ruby\n ark \"haproxy\" do\n url \"http://haproxy.1wt.eu/download/1.5/src/snapshot/haproxy-ss-20120403.tar.gz\"\n version \"1.5\"\n checksum 'ba0424bf7d23b3a607ee24bbb855bb0ea347d7ffde0bec0cb12a89623cbaf911'\n make_opts [ 'TARGET=linux26' ]\n prefix_root '/opt'\n prefix_home '/opt'\n prefix_bin '/opt/bin'\n action :install_with_make\n end\n```\n\nYou can also supply the file extension in case the file extension can not be determined by the URL:\n\n```ruby\n ark \"test_autogen\" do\n url 'https://github.com/zeromq/libzmq/tarball/master'\n extension \"tar.gz\"\n action :install_with_make\n end\n```\n\n## License & Authors\n\n- Author: Philip (flip) Kromer - Infochimps, Inc([coders@infochimps.com](mailto:coders@infochimps.com))\n- Author: Bryan W. Berry ([bryan.berry@gmail.com](mailto:bryan.berry@gmail.com))\n- Author: Denis Barishev ([denis.barishev@gmail.com](mailto:denis.barishev@gmail.com))\n- Author: Sean OMeara ([someara@chef.io](mailto:someara@chef.io))\n- Author: John Bellone ([jbellone@bloomberg.net](mailto:jbellone@bloomberg.net))\n- Copyright: 2011, Philip (flip) Kromer - Infochimps, Inc\n- Copyright: 2012, Bryan W. Berry\n- Copyright: 2012, Denis Barishev\n- Copyright: 2013-2017, Chef Software, Inc\n- Copyright: 2014, Bloomberg L.P.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","suse":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0","amazon":">= 0.0.0","windows":">= 0.0.0","mac_os_x":">= 0.0.0","smartos":">= 0.0.0","freebsd":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","windows":">= 0.0.0","seven_zip":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"ark::default":"Installs packages needed by the custom resource"},"source_url":"https://github.com/chef-cookbooks/ark","issues_url":"https://github.com/chef-cookbooks/ark/issues","chef_version":[[">= 12.7"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/ark/resources/default.rb b/cookbooks/ark/resources/default.rb index 3ca2ea1..3bcb4c4 100644 --- a/cookbooks/ark/resources/default.rb +++ b/cookbooks/ark/resources/default.rb @@ -523,6 +523,6 @@ action :configure do end end -action_class.class_eval do +action_class do include ::Ark::ProviderHelpers end diff --git a/cookbooks/build-essential/CHANGELOG.md b/cookbooks/build-essential/CHANGELOG.md index 6a94d15..e6d33f2 100644 --- a/cookbooks/build-essential/CHANGELOG.md +++ b/cookbooks/build-essential/CHANGELOG.md @@ -2,6 +2,15 @@ This file is used to list changes made in each version of the build-essential cookbook. +## 8.0.3 (2017-05-30) + +- Fix solaris metadata in metadata.rb +- Remove mac_os_x_server from metata as it's not a platform + +## 8.0.2 (2017-05-06) + +- Remove buggy action_class.class_eval usage + ## 8.0.1 (2017-04-14) - Test with local delivery and not Rake diff --git a/cookbooks/build-essential/metadata.json b/cookbooks/build-essential/metadata.json index 9478641..0b1a2fa 100644 --- a/cookbooks/build-essential/metadata.json +++ b/cookbooks/build-essential/metadata.json @@ -1 +1 @@ -{"name":"build-essential","version":"8.0.1","description":"Installs C compiler / build tools","long_description":"# build-essential Cookbook\n\n[![Cookbook Version](http://img.shields.io/cookbook/v/build-essential.svg)][cookbook] [![Build Status](https://travis-ci.org/chef-cookbooks/build-essential.svg?branch=master)](https://travis-ci.org/chef-cookbooks/build-essential)\n\nInstalls packages required for compiling C software from source. Use this cookbook if you wish to compile C programs, or install RubyGems with native extensions. Contains a resource, 'build_essential', as as well as a default recipe that simply calls that same resource.\n\n## Requirements\n\n### Platforms\n\n- Debian/Ubuntu\n- RHEL/CentOS/Scientific/Amazon/Oracle\n- openSUSE / SUSE Enterprise Linux\n- SmartOS\n- Fedora\n- Mac OS X 10.9+\n- FreeBSD\n\n### Chef\n\n- Chef 12.5+\n\n### Cookbooks\n\n- seven_zip\n- mingw\n\n**Note for Debian platform family:** On Debian platform-family systems, it is recommended that `apt-get update` be run, to ensure that the package cache is updated. It's not in the scope of this cookbook to do that, as it can [create a duplicate resource](https://tickets.chef.io/browse/CHEF-3694). We recommend using the [apt](https://supermarket.chef.io/cookbooks/apt) cookbook to do this.\n\n## Attributes\n\nAttribute | Default | Description\n------------------------------------------ | :---------------------------: | -----------------------------------------------------\n`node['build-essential']['compile_time']` | `false` | Execute resources at compile time\n`node['build-essential']['msys2']['path']` | `#{ENV['SYSTEMDRIVE']\\\\msys2` | Destination for msys2 build tool chain (Windows only)\n\n## Usage\n\n### Recipe Usage\n\nThe recipe simply calls the build_essential resource, but it ideal for adding to roles or node run lists.\n\nInclude the build-essential recipe in your run list:\n\n```sh\nknife node run_list add NODE \"recipe[build-essential::default]\"\n```\n\nor add the build-essential recipe as a dependency and include it from inside another cookbook:\n\n```ruby\ninclude_recipe 'build-essential::default'\n```\n\n### Gems with C extensions\n\nFor RubyGems that include native C extensions you wish to use with Chef, you should do the following.\n\n- Set the `compile_time` attribute to true in your wrapper cookbook or role:\n\n ```ruby\n # Wrapper attribute\n default['build-essential']['compile_time'] = true\n ```\n\n ```ruby\n # Role\n default_attributes(\n 'build-essential' => {\n 'compile_time' => true\n }\n )\n ```\n\n- Ensure that the C libraries, which include files and other assorted \"dev\"\n\n type packages, are installed in the compile phase after the build-essential\n\n recipe is executed. For example:\n\n ```ruby\n include_recipe 'build-essential::default'\n\n package('mypackage-devel') { action :nothing }.run_action(:install)\n ```\n\n- Use the `chef_gem` resource in your recipe to install the gem with the native\n\n extension:\n\n ```ruby\n chef_gem 'gem-with-native-extension'\n ```\n\n### Resource Usage\n\nThe cookbook includes a resource 'build_essential' that can be included in your cookbook to install the necessary build-essential packages\n\nSimple package installation during the client run:\n\n```ruby\nbuild_essential 'some name you choose'\n```\n\nPackage installation during the compile phase:\n\n```ruby\nbuild_essential 'some name you choose' do\n compile_time false\nend\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2009-2016, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[cookbook]: https://supermarket.chef.io/cookbooks/build-essential\n[travis]: http://travis-ci.org/chef-cookbooks/build-essential\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","freebsd":">= 0.0.0","mac_os_x":">= 10.9.0","mac_os_x_server":">= 10.9.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","smartos":">= 0.0.0","solaris":">= 0.0.0","suse":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0","zlinux":">= 0.0.0"},"dependencies":{"seven_zip":">= 0.0.0","mingw":">= 1.1"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"build-essential":"Installs packages required for compiling C software from source."},"source_url":"https://github.com/chef-cookbooks/build-essential","issues_url":"https://github.com/chef-cookbooks/build-essential/issues","chef_version":[[">= 12.5"]],"ohai_version":[]} \ No newline at end of file +{"name":"build-essential","version":"8.0.3","description":"Installs C compiler / build tools","long_description":"# build-essential Cookbook\n\n[![Cookbook Version](http://img.shields.io/cookbook/v/build-essential.svg)][cookbook] [![Build Status](https://travis-ci.org/chef-cookbooks/build-essential.svg?branch=master)](https://travis-ci.org/chef-cookbooks/build-essential)\n\nInstalls packages required for compiling C software from source. Use this cookbook if you wish to compile C programs, or install RubyGems with native extensions. Contains a resource, 'build_essential', as as well as a default recipe that simply calls that same resource.\n\n## Requirements\n\n### Platforms\n\n- Debian/Ubuntu\n- RHEL/CentOS/Scientific/Amazon/Oracle\n- openSUSE / SUSE Enterprise Linux\n- SmartOS\n- Fedora\n- Mac OS X 10.9+\n- FreeBSD\n\n### Chef\n\n- Chef 12.5+\n\n### Cookbooks\n\n- seven_zip\n- mingw\n\n**Note for Debian platform family:** On Debian platform-family systems, it is recommended that `apt-get update` be run, to ensure that the package cache is updated. It's not in the scope of this cookbook to do that, as it can [create a duplicate resource](https://tickets.chef.io/browse/CHEF-3694). We recommend using the [apt](https://supermarket.chef.io/cookbooks/apt) cookbook to do this.\n\n## Attributes\n\nAttribute | Default | Description\n------------------------------------------ | :---------------------------: | -----------------------------------------------------\n`node['build-essential']['compile_time']` | `false` | Execute resources at compile time\n`node['build-essential']['msys2']['path']` | `#{ENV['SYSTEMDRIVE']\\\\msys2` | Destination for msys2 build tool chain (Windows only)\n\n## Usage\n\n### Recipe Usage\n\nThe recipe simply calls the build_essential resource, but it ideal for adding to roles or node run lists.\n\nInclude the build-essential recipe in your run list:\n\n```sh\nknife node run_list add NODE \"recipe[build-essential::default]\"\n```\n\nor add the build-essential recipe as a dependency and include it from inside another cookbook:\n\n```ruby\ninclude_recipe 'build-essential::default'\n```\n\n### Gems with C extensions\n\nFor RubyGems that include native C extensions you wish to use with Chef, you should do the following.\n\n- Set the `compile_time` attribute to true in your wrapper cookbook or role:\n\n ```ruby\n # Wrapper attribute\n default['build-essential']['compile_time'] = true\n ```\n\n ```ruby\n # Role\n default_attributes(\n 'build-essential' => {\n 'compile_time' => true\n }\n )\n ```\n\n- Ensure that the C libraries, which include files and other assorted \"dev\"\n\n type packages, are installed in the compile phase after the build-essential\n\n recipe is executed. For example:\n\n ```ruby\n include_recipe 'build-essential::default'\n\n package('mypackage-devel') { action :nothing }.run_action(:install)\n ```\n\n- Use the `chef_gem` resource in your recipe to install the gem with the native\n\n extension:\n\n ```ruby\n chef_gem 'gem-with-native-extension'\n ```\n\n### Resource Usage\n\nThe cookbook includes a resource 'build_essential' that can be included in your cookbook to install the necessary build-essential packages\n\nSimple package installation during the client run:\n\n```ruby\nbuild_essential 'some name you choose'\n```\n\nPackage installation during the compile phase:\n\n```ruby\nbuild_essential 'some name you choose' do\n compile_time false\nend\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2009-2016, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[cookbook]: https://supermarket.chef.io/cookbooks/build-essential\n[travis]: http://travis-ci.org/chef-cookbooks/build-essential\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","freebsd":">= 0.0.0","mac_os_x":">= 10.9.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","smartos":">= 0.0.0","solaris2":">= 0.0.0","suse":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0","zlinux":">= 0.0.0"},"dependencies":{"seven_zip":">= 0.0.0","mingw":">= 1.1"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"build-essential":"Installs packages required for compiling C software from source."},"source_url":"https://github.com/chef-cookbooks/build-essential","issues_url":"https://github.com/chef-cookbooks/build-essential/issues","chef_version":[[">= 12.5"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/build-essential/resources/xcode_command_line_tools.rb b/cookbooks/build-essential/resources/xcode_command_line_tools.rb index 9e7f5d8..4c75cf1 100644 --- a/cookbooks/build-essential/resources/xcode_command_line_tools.rb +++ b/cookbooks/build-essential/resources/xcode_command_line_tools.rb @@ -44,7 +44,7 @@ action :install do end end -action_class.class_eval do +action_class do # # Determine if the XCode Command Line Tools are installed # diff --git a/cookbooks/chef_client_updater/CHANGELOG.md b/cookbooks/chef_client_updater/CHANGELOG.md index fbbad7f..6870e07 100644 --- a/cookbooks/chef_client_updater/CHANGELOG.md +++ b/cookbooks/chef_client_updater/CHANGELOG.md @@ -2,6 +2,23 @@ This file is used to list changes made in each version of the chef_client_updater cookbook. +## 1.1.1 (2017-05-11) + +- Fix the initial load of mixlib-install failing + + +## 1.1.0 (2017-05-10) + +- Add support for download URL overrides via new properties on the resource and attributes for the default recipe. This requires mixlib-install 3.2.1, which we now ensure we install in the updater resource. +- Update the default post_install action in the recipe to match the resource (exec). +- Remove usage of class_eval in the resource since we use compat_resource and class_eval causes issues with some later Chef 12 releases. +- Fix the solaris platform name in the metadata.rb. +- Remove disabling FC016 and FC023 Foodcritic rules as these no longer alert. +- Avoid infinite loops if trying to install the latest chef-client version from any channel. +- Add a true test recipe and remove unused inspec tests +- Add debug logging of the current vs. desired versions to help troubleshooting +- Added a blurb in the readme outlining init system issues surrounding kill and the chef-client starting back up + ## 1.0.2 (2017-04-07) - Fix Chef 13 compatibility by using Kernel.exec not exec diff --git a/cookbooks/chef_client_updater/README.md b/cookbooks/chef_client_updater/README.md index 6ce141a..a3faaa0 100644 --- a/cookbooks/chef_client_updater/README.md +++ b/cookbooks/chef_client_updater/README.md @@ -18,10 +18,16 @@ This cookbook updates the chef-client - compat_resource -### Usage +## Usage This cookbook provides both a custom resource and a default recipe. The default recipe simply uses the custom resource with a set of attributes. You can add chef_client_updater::default to your run list or use the custom resource in a wrapper cookbook. +### Init System Caveats + +When Chef runs as a service under a system init daemon such as Sys-V or systemd each chef run forks off from the main chef-client process being managed by the init system. For a chef-client upgrade to occur the running chef-client as well as the parent process must be killed, and a new chef-client must start using the updated binaries. This cookbook handles killing the chef-client, but your init system must properly handle starting the service back up. For systemd and upstart this can be handled via configuration, and chef-client cookbook 8.1.1 or later handles this by default. This functionality is not available in sys-v (RHEL 6, Debian 7, and others), so you will need to employ a secondary process such as a monitoring system to start the chef-client service. + +## Resources + ### chef_client_updater Installs the mixlib-install/mixlib-install gems and upgrades the chef-client. @@ -34,6 +40,8 @@ Installs the mixlib-install/mixlib-install gems and upgrades the chef-client. - `post_install_action` - After installing the chef-client what should we do. `exec` to exec the new client or `kill` to kill the client and rely on the init system to start up the new version. Default: `exec` - `exec_command` - The chef-client command. default: $PROGRAM_NAME.split(' ').first - `exec_args` - An array of arguments to exec the chef-client with. default: ARGV +- `download_url_override` - The direct URL for the chef-client package. +- `checksum` - The SHA-256 checksum of the chef-client package from the direct URL. #### examples diff --git a/cookbooks/chef_client_updater/attributes/default.rb b/cookbooks/chef_client_updater/attributes/default.rb index 9ff102d..fb006f7 100644 --- a/cookbooks/chef_client_updater/attributes/default.rb +++ b/cookbooks/chef_client_updater/attributes/default.rb @@ -26,4 +26,10 @@ default['chef_client_updater']['prevent_downgrade'] = true default['chef_client_updater']['version'] = 'latest' # kill the client post install or exec the client post install for non-service based installs -default['chef_client_updater']['post_install_action'] = 'kill' +default['chef_client_updater']['post_install_action'] = 'exec' + +# the download URL (for use in an air-gapped environment) +default['chef_client_updater']['download_url_override'] = nil + +# the checksum of the package from "download_url_override" +default['chef_client_updater']['checksum'] = nil diff --git a/cookbooks/chef_client_updater/metadata.json b/cookbooks/chef_client_updater/metadata.json index 6237129..703a258 100644 --- a/cookbooks/chef_client_updater/metadata.json +++ b/cookbooks/chef_client_updater/metadata.json @@ -1 +1 @@ -{"name":"chef_client_updater","version":"1.0.2","description":"Upgrades chef-client to specified releases","long_description":"Upgrades chef-client to specified releases","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","mac_os_x":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","solaris":">= 0.0.0","suse":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0","aix":">= 0.0.0"},"dependencies":{"compat_resource":">= 12.16.3"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/chef_client_updater","issues_url":"https://github.com/chef-cookbooks/chef_client_updater/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file +{"name":"chef_client_updater","version":"1.1.1","description":"Upgrades chef-client to specified releases","long_description":"Upgrades chef-client to specified releases","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","mac_os_x":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","solaris2":">= 0.0.0","suse":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0","aix":">= 0.0.0"},"dependencies":{"compat_resource":">= 12.16.3"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/chef_client_updater","issues_url":"https://github.com/chef-cookbooks/chef_client_updater/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/chef_client_updater/recipes/default.rb b/cookbooks/chef_client_updater/recipes/default.rb index c900dc7..980ce46 100644 --- a/cookbooks/chef_client_updater/recipes/default.rb +++ b/cookbooks/chef_client_updater/recipes/default.rb @@ -22,4 +22,6 @@ chef_client_updater 'update chef-client' do version node['chef_client_updater']['version'] prevent_downgrade node['chef_client_updater']['prevent_downgrade'] post_install_action node['chef_client_updater']['post_install_action'] + download_url_override node['chef_client_updater']['download_url_override'] if node['chef_client_updater']['download_url_override'] + checksum node['chef_client_updater']['checksum'] if node['chef_client_updater']['checksum'] end diff --git a/cookbooks/chef_client_updater/resources/updater.rb b/cookbooks/chef_client_updater/resources/updater.rb index c75bb24..b429781 100644 --- a/cookbooks/chef_client_updater/resources/updater.rb +++ b/cookbooks/chef_client_updater/resources/updater.rb @@ -26,9 +26,11 @@ property :version, [String, Symbol], default: :latest property :post_install_action, String, default: 'exec' property :exec_command, String, default: $PROGRAM_NAME.split(' ').first property :exec_args, Array, default: ARGV +property :download_url_override, String +property :checksum, String action :update do - if update_necessary? # ~FC023 + if update_necessary? converge_by "Upgraded chef-client #{current_version} to #{desired_version}" do upgrade_command = Mixlib::ShellOut.new(mixlib_install.install_command) upgrade_command.run_command @@ -37,12 +39,14 @@ action :update do end end -action_class.class_eval do +action_class do def load_mixlib_install + gem 'mixlib-install', '~> 3.2', '>= 3.2.1' require 'mixlib/install' rescue LoadError Chef::Log.info('mixlib-install gem not found. Installing now') chef_gem 'mixlib-install' do + version '>= 3.2.1' compile_time true if respond_to?(:compile_time) end @@ -69,6 +73,9 @@ action_class.class_eval do product_version: new_resource.version == 'latest' ? :latest : new_resource.version, } + if new_resource.download_url_override && new_resource.checksum + options[:install_command_options] = { download_url_override: new_resource.download_url_override, checksum: new_resource.checksum } + end Mixlib::Install.new(options) end @@ -80,7 +87,7 @@ action_class.class_eval do end def desired_version - new_resource.version == 'latest' ? mixlib_install.available_versions.last : new_resource.version + new_resource.version.to_sym == :latest ? mixlib_install.available_versions.last : new_resource.version end # why wouldn't we use the built in update_available? method in mixlib-install? @@ -90,6 +97,7 @@ action_class.class_eval do load_mixlib_versioning cur_version = Mixlib::Versioning.parse(current_version) des_version = Mixlib::Versioning.parse(desired_version) + Chef::Log.debug("The current chef-client version is #{cur_version} and the desired version is #{desired_version}") new_resource.prevent_downgrade ? (des_version > cur_version) : (des_version != cur_version) end diff --git a/cookbooks/chef_nginx/CHANGELOG.md b/cookbooks/chef_nginx/CHANGELOG.md index 944141f..3987735 100644 --- a/cookbooks/chef_nginx/CHANGELOG.md +++ b/cookbooks/chef_nginx/CHANGELOG.md @@ -2,6 +2,21 @@ This file is used to list changes made in each version of the nginx cookbook. +## 6.1.1 (2017-06-08) + +- Use multipackage installs in the pagespeed recipe to speed things up +- Several fixes for Amazon Linux on Chef 13+ + +## 6.1.0 (2017-06-07) + +- Add attributes for setting the repository URLs +- Fix support for Amazon Linux repos on Chef 13+ + + +## 6.0.3 (2017-06-05) + +- Correctly compare nginx versions with multiple digits so 1.10 is properly recognized as coming after 1.2. + ## 6.0.2 (2017-04-27) - Resolve name conflicts in the resource diff --git a/cookbooks/chef_nginx/README.md b/cookbooks/chef_nginx/README.md index d049f10..249f795 100644 --- a/cookbooks/chef_nginx/README.md +++ b/cookbooks/chef_nginx/README.md @@ -26,11 +26,11 @@ The following cookbooks are direct dependencies because they're used for common The following platforms are supported and tested with Test Kitchen: -- Ubuntu 12.04+ -- CentOS 5+ +- Ubuntu 14.04+ +- CentOS 6+ - Debian 7+ -- openSUSE 13.2+ -- FreeBSD 9+ +- openSUSE +- FreeBSD Other Debian and RHEL family distributions are assumed to work. @@ -119,14 +119,6 @@ Generally used attributes. Some have platform specific values. See `attributes/d - `node['nginx']['extra_configs']` - a Hash of key/values to nginx configuration. -### chef_nginx::echo - -These attributes are used in the `chef_nginx::http_echo_module` recipe. - -- `node['nginx']['echo']['version']` - The version of `http_echo` you want (default: 0.59) -- `node['nginx']['echo']['url']` - URL for the tarball. -- `node['nginx']['echo']['checksum']` - Checksum of the tarball. - ### chef_nginx::devel These attributes are used in the `chef_nginx::ngx_devel_module` recipe. @@ -135,6 +127,14 @@ These attributes are used in the `chef_nginx::ngx_devel_module` recipe. - `node['nginx']['devel']['url']` - The URL of the nginx devel module tar.gz file - `node['nginx']['devel']['checksum']` - The checksum of the nginx devel module tar.gz file +### chef_nginx::echo + +These attributes are used in the `chef_nginx::http_echo_module` recipe. + +- `node['nginx']['echo']['version']` - The version of `http_echo` you want (default: 0.59) +- `node['nginx']['echo']['url']` - URL for the tarball. +- `node['nginx']['echo']['checksum']` - Checksum of the tarball. + ### chef_nginx::geoip These attributes are used in the `chef_nginx::http_geoip_module` recipe. Please note that the `country_dat_checksum` and `city_dat_checksum` are based on downloads from a datacenter in Fremont, CA, USA. You really should override these with checksums for the geo tarballs from your node location. @@ -159,6 +159,13 @@ From: - `node['nginx']['realip']['addresses']` - Addresses to use for the `http_realip` configuration. - `node['nginx']['realip']['real_ip_recursive']` - If recursive search is enabled, the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the request header field. Can be on "on" or "off" (default). +### chef_nginx::openssl_source + +These attributes are used in the `chef_nginx::openssl_source` recipe. + +- `node['nginx']['openssl_source']['version']` - The version of OpenSSL you want to download and use (default: 1.0.1t) +- `node['nginx']['openssl_source']['url']` - The url for the OpenSSL source + ### chef_nginx::passenger These attributes are used in the `chef_nginx::passenger` recipe. @@ -184,13 +191,6 @@ Basic configuration to use the official Phusion Passenger repositories: - `node['nginx']['package_name']` - 'nginx-extras' - `node['nginx']['passenger']['install_method']` - 'package' -### chef_nginx::openssl_source - -These attributes are used in the `chef_nginx::openssl_source` recipe. - -- `node['nginx']['openssl_source']['version']` - The version of OpenSSL you want to download and use (default: 1.0.1t) -- `node['nginx']['openssl_source']['url']` - The url for the OpenSSL source - ### chef_nginx::rate_limiting - `node['nginx']['enable_rate_limiting']` - set to true to enable rate limiting (`limit_req_zone` in nginx.conf) @@ -198,6 +198,11 @@ These attributes are used in the `chef_nginx::openssl_source` recipe. - `node['nginx']['rate_limiting_backoff']` - sets the backoff time for `limit_req_zone`. - `node['nginx']['rate_limit']` - set the rate limit amount for `limit_req_zone`. +### chef_nginx::repo + +- `node['nginx']['upstream_repository']` - the URL to use for the package repository resource; default is set based on platform type +- `node['nginx']['repo_signing_key']` - The URL from which package signing/gpg key is retrieved + ### chef_nginx::socketproxy These attributes are used in the `chef_nginx::socketproxy` recipe. diff --git a/cookbooks/chef_nginx/attributes/default.rb b/cookbooks/chef_nginx/attributes/default.rb index e2000eb..ac1dbf4 100644 --- a/cookbooks/chef_nginx/attributes/default.rb +++ b/cookbooks/chef_nginx/attributes/default.rb @@ -41,11 +41,7 @@ default['nginx']['repo_source'] = 'nginx' default['nginx']['install_method'] = 'package' case node['platform_family'] -when 'debian' - default['nginx']['user'] = 'www-data' -when 'rhel' - default['nginx']['user'] = 'nginx' -when 'fedora' +when 'rhel', 'fedora', 'amazon' default['nginx']['user'] = 'nginx' when 'freebsd' default['nginx']['package_name'] = 'www/nginx' @@ -57,7 +53,7 @@ when 'freebsd' when 'suse' default['nginx']['user'] = 'wwwrun' default['nginx']['group'] = 'www' -else +else # debian probably default['nginx']['user'] = 'www-data' end diff --git a/cookbooks/chef_nginx/attributes/repo.rb b/cookbooks/chef_nginx/attributes/repo.rb index b170bd8..ea334fc 100644 --- a/cookbooks/chef_nginx/attributes/repo.rb +++ b/cookbooks/chef_nginx/attributes/repo.rb @@ -19,17 +19,24 @@ # limitations under the License. # -case node['platform_family'] -when 'rhel', 'fedora' - default['nginx']['upstream_repository'] = case node['platform'] - when 'centos' - # See http://wiki.nginx.org/Install - "http://nginx.org/packages/centos/#{node['platform_version'].to_i}/$basearch/" - when 'amazon' - 'http://nginx.org/packages/rhel/6/$basearch/' - else - "http://nginx.org/packages/rhel/#{node['platform_version'].to_i}/$basearch/" - end -when 'debian' - default['nginx']['upstream_repository'] = "http://nginx.org/packages/#{node['platform']}" -end +default['nginx']['upstream_repository'] = + case node['platform_family'] + when 'amazon' # Chef 13+ on amazon linux + 'http://nginx.org/packages/rhel/6/$basearch/' + when 'rhel', 'fedora' + case node['platform'] + when 'centos' + # See http://wiki.nginx.org/Install + "http://nginx.org/packages/centos/#{node['platform_version'].to_i}/$basearch/" + when 'amazon' # Chef < 13 on Amazon + 'http://nginx.org/packages/rhel/6/$basearch/' + else + "http://nginx.org/packages/rhel/#{node['platform_version'].to_i}/$basearch/" + end + when 'debian' + "http://nginx.org/packages/#{node['platform']}" + when 'suse' + 'http://nginx.org/packages/sles/12' + end + +default['nginx']['repo_signing_key'] = 'http://nginx.org/keys/nginx_signing.key' diff --git a/cookbooks/chef_nginx/libraries/nginx_version.rb b/cookbooks/chef_nginx/libraries/nginx_version.rb new file mode 100644 index 0000000..957267a --- /dev/null +++ b/cookbooks/chef_nginx/libraries/nginx_version.rb @@ -0,0 +1,37 @@ +class NginxVersion + include Comparable + + attr_reader :version + + def initialize(version) + @version = version + end + + def <=>(other) + lhsegments = segments + rhsegments = other.segments + + parts = [lhsegments.size, rhsegments.size].max + + (0..(parts - 1)).each do |index| + lhs = lhsegments[index] || 0 + rhs = rhsegments[index] || 0 + + next if lhs == rhs + + return lhs <=> rhs + end + + 0 + end + + def to_s + version + end + + protected + + def segments + version.split('.').map { |part| Integer(part) } + end +end diff --git a/cookbooks/chef_nginx/metadata.json b/cookbooks/chef_nginx/metadata.json index 2adb415..3a4fe56 100644 --- a/cookbooks/chef_nginx/metadata.json +++ b/cookbooks/chef_nginx/metadata.json @@ -1 +1 @@ -{"name":"chef_nginx","version":"6.0.2","description":"Installs and configures nginx","long_description":"# nginx Cookbook\n\n[![Cookbook](http://img.shields.io/cookbook/v/chef_nginx.svg)](https://supermarket.chef.io/cookbooks/chef_nginx) [![Build Status](https://travis-ci.org/chef-cookbooks/chef_nginx.svg?branch=master)](https://travis-ci.org/chef-cookbooks/chef_nginx)\n\nInstalls nginx from package OR source code and sets up configuration handling similar to Debian's Apache2 scripts.\n\n## nginx vs. chef_nginx\n\nThis cookbook is a fork from the 2.7.x branch of the [community nginx cookbook](https://github.com/miketheman/nginx).\n\nThis fork will be actively supported by Chef Software and we will continue to migrate the cookbook to a more resource driven model, with incremental changes following the SemVer model.\n\n## Requirements\n\n### Cookbooks\n\nThe following cookbooks are direct dependencies because they're used for common \"default\" functionality.\n\n- `build-essential` for source installations\n- `ohai` for setting up the ohai plugin\n- `compat_resource` for setting up the nginx.org repository on Chef 12.1 - 12.13\n- `yum-epel` for setting up the EPEL repository on RHEL platforms\n- `zypper` for setting up the nginx.org repository on Suse platforms\n\n### Platforms\n\nThe following platforms are supported and tested with Test Kitchen:\n\n- Ubuntu 12.04+\n- CentOS 5+\n- Debian 7+\n- openSUSE 13.2+\n- FreeBSD 9+\n\nOther Debian and RHEL family distributions are assumed to work.\n\n### Chef\n\n- Chef 12.1+\n\n## Attributes\n\nNode attributes for this cookbook are logically separated into different files. Some attributes are set only via a specific recipe.\n\n### chef_nginx::auth_request\n\nThese attributes are used in the `chef_nginx::auth_request` recipe.\n\n- `node['nginx']['auth_request']['url']` - The url to the auth_request module tar.gz file\n- `node['nginx']['auth_request']['checksum']` - The checksum of the auth_request module tar.gz file\n\n### chef_nginx::default\n\nGenerally used attributes. Some have platform specific values. See `attributes/default.rb`. \"The Config\" refers to \"nginx.conf\" the main config file.\n\n- `node['nginx']['dir']` - Location for nginx configuration.\n- `node['nginx']['conf_template']` - The `source` template to use when creating the `nginx.conf`.\n- `node['nginx']['conf_cookbook']` - The cookbook where `node['nginx']['conf_template']` resides.\n- `node['nginx']['log_dir']` - Location for nginx logs.\n- `node['nginx']['log_dir_perm']` - Permissions for nginx logs folder.\n- `node['nginx']['user']` - User that nginx will run as.\n- `node['nginx']['group']` - Group for nginx.\n- `node['nginx']['port']` - Port for nginx to listen on.\n- `node['nginx']['binary']` - Path to the nginx binary.\n- `node['nginx']['init_style']` - How to run nginx as a service when using `chef_nginx::source`. Values can be \"upstart\", \"systemd\", or \"init\". This attribute is not used in the `package` recipe because the package manager's init script style for the platform is assumed.\n- `node['nginx']['upstart']['foreground']` - Set this to true if you want upstart to run nginx in the foreground, set to false if you want upstart to detach and track the process via pid.\n- `node['nginx']['upstart']['runlevels']` - String of runlevels in the format '2345' which determines which runlevels nginx will start at when entering and stop at when leaving.\n- `node['nginx']['upstart']['respawn_limit']` - Respawn limit in upstart stanza format, count followed by space followed by interval in seconds.\n- `node['nginx']['keepalive']` - Whether to use `keepalive_timeout`, any value besides \"on\" will leave that option out of the config.\n- `node['nginx']['keepalive_requests']` - used for config value of `keepalive_requests`.\n- `node['nginx']['keepalive_timeout']` - used for config value of `keepalive_timeout`.\n- `node['nginx']['worker_processes']` - used for config value of `worker_processes`.\n- `node['nginx']['worker_connections']` - used for config value of `events { worker_connections }`\n- `node['nginx']['worker_rlimit_nofile']` - used for config value of `worker_rlimit_nofile`. Can replace any \"ulimit -n\" command. The value depend on your usage (cache or not) but must always be superior than worker_connections.\n- `node['nginx']['worker_shutdown_timeout']` - used for config value of `worker_shutdown_timeout`.\n- `node['nginx']['worker_connections']` - used for config value of `events { worker_connections }`\n- `node['nginx']['multi_accept']` - used for config value of `events { multi_accept }`. Try to accept() as many connections as possible. Disable by default.\n- `node['nginx']['event']` - used for config value of `events { use }`. Set the event-model. By default nginx looks for the most suitable method for your OS.\n- `node['nginx']['accept_mutex_delay']` - used for config value of `accept_mutex_delay`\n- `node['nginx']['server_tokens']` - used for config value of `server_tokens`.\n- `node['nginx']['server_names_hash_bucket_size']` - used for config value of `server_names_hash_bucket_size`.\n- `node['nginx']['disable_access_log']` - set to true to disable the general access log, may be useful on high traffic sites.\n- `node['nginx']['access_log_options']` - Set to a string of additional options to be appended to the access log directive\n- `node['nginx']['error_log_options']` - Set to a string of additional options to be appended to the error log directive\n- `node['nginx']['default_site_enabled']` - enable the default site\n- `node['nginx']['sendfile']` - Whether to use `sendfile`. Defaults to \"on\".\n- `node['nginx']['tcp_nopush']` - Whether to use `tcp_nopush`. Defaults to \"on\".\n- `node['nginx']['tcp_nodelay']` - Whether to use `tcp_nodelay`. Defaults to \"on\".\n- `node['nginx']['install_method']` - Whether nginx is installed from packages or from source.\n- `node['nginx']['types_hash_max_size']` - Used for the `types_hash_max_size` configuration directive.\n- `node['nginx']['types_hash_bucket_size']` - Used for the `types_hash_bucket_size` configuration directive.\n- `node['nginx']['proxy_read_timeout']` - defines a timeout (between two successive read operations) for reading a response from the proxied server.\n- `node['nginx']['client_body_buffer_size']` - used for config value of `client_body_buffer_size`.\n- `node['nginx']['client_max_body_size']` - specifies the maximum accepted body size of a client request, as indicated by the request header Content-Length.\n- `node['nginx']['repo_source']` - when installed from a package this attribute affects which yum repositories, if any, will be added before installing the nginx package. The default value of 'epel' will use the `yum-epel` cookbook, 'nginx' will use the `chef_nginx::repo` recipe, 'passenger' will use the 'chef_nginx::repo_passenger' recipe, and setting no value will not add any additional repositories.\n- `node['nginx']['sts_max_age']` - Enable Strict Transport Security for all apps (See: ). This attribute adds the following header: Strict-Transport-Security max-age=SECONDS to all incoming requests and takes an integer (in seconds) as its argument.\n- `node['nginx']['default']['modules']` - Array specifying which modules to enable via the conf-enabled config include function. Currently the only valid value is \"socketproxy\".\n- `node['nginx']['load_modules']` - Array of paths to modules to dynamically load on nginx startup using the `load_module` directive. Default is `[]`.\n\n#### authorized_ips module\n\n- `node['nginx']['remote_ip_var']` - The remote ip variable name to use.\n- `node['nginx']['authorized_ips']` - IPs authorized by the module\n\n#### gzip module\n\n- `node['nginx']['gzip']` - Whether to use gzip, can be \"on\" or \"off\"\n- `node['nginx']['gzip_http_version']` - used for config value of `gzip_http_version`.\n- `node['nginx']['gzip_comp_level']` - used for config value of `gzip_comp_level`.\n- `node['nginx']['gzip_proxied']` - used for config value of `gzip_proxied`.\n- `node['nginx']['gzip_vary']` - used for config value of `gzip_vary`.\n- `node['nginx']['gzip_buffers']` - used for config value of `gzip_buffers`.\n- `node['nginx']['gzip_types']` - used for config value of `gzip_types` - must be an Array.\n- `node['nginx']['gzip_min_length']` - used for config value of `gzip_min_length`.\n- `node['nginx']['gzip_disable']` - used for config value of `gzip_disable`.\n- `node['nginx']['gzip_static']` - used for config value of `gzip_static` (`http_gzip_static_module` must be enabled)\n\n#### Other configurations\n\n- `node['nginx']['extra_configs']` - a Hash of key/values to nginx configuration.\n\n### chef_nginx::echo\n\nThese attributes are used in the `chef_nginx::http_echo_module` recipe.\n\n- `node['nginx']['echo']['version']` - The version of `http_echo` you want (default: 0.59)\n- `node['nginx']['echo']['url']` - URL for the tarball.\n- `node['nginx']['echo']['checksum']` - Checksum of the tarball.\n\n### chef_nginx::devel\n\nThese attributes are used in the `chef_nginx::ngx_devel_module` recipe.\n\n- `node['nginx']['devel']['version']` - The version of the nginx devel module\n- `node['nginx']['devel']['url']` - The URL of the nginx devel module tar.gz file\n- `node['nginx']['devel']['checksum']` - The checksum of the nginx devel module tar.gz file\n\n### chef_nginx::geoip\n\nThese attributes are used in the `chef_nginx::http_geoip_module` recipe. Please note that the `country_dat_checksum` and `city_dat_checksum` are based on downloads from a datacenter in Fremont, CA, USA. You really should override these with checksums for the geo tarballs from your node location.\n\n**Note** The upstream, maxmind.com, may block access for repeated downloads of the data files. It is recommended that you download and host the data files, and change the URLs in the attributes.\n\n- `node['nginx']['geoip']['path']` - Location where to install the geoip libraries.\n- `node['nginx']['geoip']['enable_city']` - Whether to enable City data\n- `node['nginx']['geoip']['country_dat_url']` - Country data tarball URL\n- `node['nginx']['geoip']['country_dat_checksum']` - Country data tarball checksum\n- `node['nginx']['geoip']['city_dat_url']` - City data tarball URL\n- `node['nginx']['geoip']['city_dat_checksum']` - City data tarball checksum\n- `node['nginx']['geoip']['lib_version']` - Version of the GeoIP library to install\n- `node['nginx']['geoip']['lib_url']` - (Versioned) Tarball URL of the GeoIP library\n- `node['nginx']['geoip']['lib_checksum']` - Checksum of the GeoIP library tarball\n\n### chef_nginx::http_realip_module\n\nFrom: \n\n- `node['nginx']['realip']['header']` - Header to use for the RealIp Module; only accepts \"X-Forwarded-For\" or \"X-Real-IP\"\n- `node['nginx']['realip']['addresses']` - Addresses to use for the `http_realip` configuration.\n- `node['nginx']['realip']['real_ip_recursive']` - If recursive search is enabled, the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the request header field. Can be on \"on\" or \"off\" (default).\n\n### chef_nginx::passenger\n\nThese attributes are used in the `chef_nginx::passenger` recipe.\n\n- `node['nginx']['passenger']['version']` - passenger gem version\n- `node['nginx']['passenger']['root']` - passenger gem root path\n- `node['nginx']['passenger']['install_rake']` - set to false if rake already present on system\n- `node['nginx']['passenger']['max_pool_size']` - maximum passenger pool size (default=10)\n- `node['nginx']['passenger']['ruby']` - Ruby path for Passenger to use (default=`$(which ruby)`)\n- `node['nginx']['passenger']['spawn_method']` - passenger spawn method to use (default=`smart-lv2`)\n- `node['nginx']['passenger']['buffer_response']` - turns on or off response buffering (default=`on`)\n- `node['nginx']['passenger']['max_pool_size']` - passenger maximum pool size (default=`6`)\n- `node['nginx']['passenger']['min_instances']` - minimum instances (default=`1`)\n- `node['nginx']['passenger']['max_instances_per_app']` - maximum instances per app (default=`0`)\n- `node['nginx']['passenger']['pool_idle_time']` - passenger pool idle time (default=`300`)\n- `node['nginx']['passenger']['max_requests']` - maximum requests (default=`0`)\n- `node['nginx']['passenger']['nodejs']` - Nodejs path for Passenger to use (default=nil)\n- `node['nginx']['passenger']['show_version_in_header']` - Show passenger version in HTTP headers (default=`on`)\n\nBasic configuration to use the official Phusion Passenger repositories:\n\n- `node['nginx']['repo_source']` - 'passenger'\n- `node['nginx']['package_name']` - 'nginx-extras'\n- `node['nginx']['passenger']['install_method']` - 'package'\n\n### chef_nginx::openssl_source\n\nThese attributes are used in the `chef_nginx::openssl_source` recipe.\n\n- `node['nginx']['openssl_source']['version']` - The version of OpenSSL you want to download and use (default: 1.0.1t)\n- `node['nginx']['openssl_source']['url']` - The url for the OpenSSL source\n\n### chef_nginx::rate_limiting\n\n- `node['nginx']['enable_rate_limiting']` - set to true to enable rate limiting (`limit_req_zone` in nginx.conf)\n- `node['nginx']['rate_limiting_zone_name']` - sets the zone in `limit_req_zone`.\n- `node['nginx']['rate_limiting_backoff']` - sets the backoff time for `limit_req_zone`.\n- `node['nginx']['rate_limit']` - set the rate limit amount for `limit_req_zone`.\n\n### chef_nginx::socketproxy\n\nThese attributes are used in the `chef_nginx::socketproxy` recipe.\n\n- `node['nginx']['socketproxy']['root']` - The directory (on your server) where socketproxy apps are deployed.\n- `node['nginx']['socketproxy']['default_app']` - Static assets directory for requests to \"/\" that don't meet any proxy_pass filter requirements.\n- `node['nginx']['socketproxy']['apps']['app_name']['prepend_slash']` - Prepend a slash to requests to app \"app_name\" before sending them to the socketproxy socket.\n- `node['nginx']['socketproxy']['apps']['app_name']['context_name']` - URI (e.g. \"app_name\" in order to achieve \"\") at which to host the application \"app_name\"\n- `node['nginx']['socketproxy']['apps']['app_name']['subdir']` - Directory (under `node['nginx']['socketproxy']['root']`) in which to find the application.\n\n### chef_nginx::source\n\nThese attributes are used in the `chef_nginx::source` recipe. Some of them are dynamically modified during the run. See `attributes/source.rb` for default values.\n\n- `node['nginx']['source']['url']` - (versioned) URL for the nginx source code. By default this will use the version specified as `node['nginx']['version']`.\n- `node['nginx']['source']['prefix']` - (versioned) prefix for installing nginx from source\n- `node['nginx']['source']['conf_path']` - location of the main config file, in `node['nginx']['dir']` by default.\n- `node['nginx']['source']['modules']` - Array of modules that should be compiled into nginx by including their recipes in `chef_nginx::source`.\n- `node['nginx']['source']['default_configure_flags']` - The default flags passed to the configure script when building nginx.\n- `node['nginx']['configure_flags']` - Preserved for compatibility and dynamically generated from the `node['nginx']['source']['default_configure_flags']` in the `chef_nginx::source` recipe.\n- `node['nginx']['source']['use_existing_user']` - set to `true` if you do not want `chef_nginx::source` recipe to create system user with name `node['nginx']['user']`.\n\n### chef_nginx::status\n\nThese attributes are used in the `chef_nginx::http_stub_status_module` recipe.\n\n- `node['nginx']['status']['port']` - The port on which nginx will serve the status info (default: 8090)\n\n### chef_nginx::syslog\n\nThese attributes are used in the `chef_nginx::syslog_module` recipe.\n\n- `node['nginx']['syslog']['git_repo']` - The git repository url to use for the syslog patches.\n- `node['nginx']['syslog']['git_revision']` - The revision on the git repository to checkout.\n\n### chef_nginx::upload_progress\n\nThese attributes are used in the `chef_nginx::upload_progress_module` recipe.\n\n- `node['nginx']['upload_progress']['url']` - URL for the tarball.\n- `node['nginx']['upload_progress']['checksum']` - Checksum of the tarball.\n- `node['nginx']['upload_progress']['javascript_output']` - Output in javascript. Default is `true` for backwards compatibility.\n- `node['nginx']['upload_progress']['zone_name']` - Zone name which will be used to store the per-connection tracking information. Default is `proxied`.\n- `node['nginx']['upload_progress']['zone_size']` - Zone size in bytes. Default is `1m` (1 megabyte).\n\n## Resources\n\n### nginx_site\n\nEnable or disable a Server Block in `#{node['nginx']['dir']}/sites-available` by calling nxensite or nxdissite (introduced by this cookbook) to manage the symbolic link in `#{node['nginx']['dir']}/sites-enabled`.\n\n### Actions\n\n- `enable` - Enable the nginx site (default)\n- `disable` - Disable the nginx site\n\n### Properties:\n\n- `name` - (optional) Name of the site to enable. By default it's assumed that the name of the nginx_site resource is the site name, but this allows overriding that.\n- `template` - (optional) Path to the source for the `template` resource.\n- `variables` - (optional) Variables to be used with the `template` resource\n\n## Ohai Plugin\n\nThe `ohai_plugin` recipe includes an Ohai plugin. It will be automatically installed and activated, providing the following attributes via ohai, no matter how nginx is installed (source or package):\n\n- `node['nginx']['version']` - version of nginx\n- `node['nginx']['configure_arguments']` - options passed to `./configure` when nginx was built\n- `node['nginx']['prefix']` - installation prefix\n- `node['nginx']['conf_path']` - configuration file path\n\nIn the source recipe, it is used to determine whether control attributes for building nginx have changed.\n\n## Usage\n\nThis cookbook provides three distinct installation methods, all of which are controlled via attributes and executed using the chef_nginx::default recipe.\n\n### Package installation using the nginx.org repositories\n\nNginx provides repositories for RHEL, Debian/Ubuntu, and Suse platforms with up to date packages available on older distributions. Due to the age of many nginx packages shipping with distros we believe this is the ideal installation method. With no attributes set the nginx.org repositories will be added to your system and nginx will be installed via package. This provides a solid out of the box install for most users.\n\n### Package installation using distro repositories\n\nIf you prefer to use the packages included in your distro or to roll your own packages you'll want to set `node['nginx']['repo_source']` to `nil` or `distro` to skip the repository setup. The default recipe will still install nginx from packages, but you'll retain control over the package location.\n\n### Source installation to compile non-dynamic modules\n\nIf you need control over how nginx is built, or you need non-dynamic modules to be included you'll need to compile nginx from source. We highly recommend against using this method as it requires the installation of a full compilation toolchain and development dependencies on your nodes. Creating your own packages with nginx compiled as necessary is a preferred option. If that's not possible you can set `node['nginx']['install_method']` to `source` and provide a version in `node['nginx']['version']`.\n\n#### Specifying Modules to compile\n\nThe following recipes are used to build module support into nginx. To compile a module, add its recipe name to the array attribute `node['nginx']['source']['modules']`.\n\n- `ipv6.rb` - enables IPv6 support\n- `headers_more_module` -\n- `http_auth_request_module``\n- `http_echo_module.rb` - downloads the `http_echo_module` module and enables it as a module when compiling nginx.\n- `http_geoip_module.rb` - installs the GeoIP libraries and data files and enables the module for compilation.\n- `http_gzip_static_module.rb` - enables the module for compilation. Be sure to set `node['nginx']['gzip_static'] = 'yes'`.\n- `http_mp4_module` -\n- `http_perl_module.rb` - enables embedded Perl for compilation.\n- `http_realip_module.rb` - enables the module for compilation and creates the configuration.\n- `http_spdy_module` -\n- `http_ssl_module.rb` - enables SSL for compilation.\n- `http_stub_status_module.rb` - provides `nginx_status` configuration and enables the module for compilation.\n- `http_v2_module`\n- `ipv6` -\n- `naxsi_module` - enables the naxsi module for the web application firewall for nginx.\n- `ngx_devel_module` -\n- `ngx_lua_module` -\n- `openssl_source.rb` - downloads and uses custom OpenSSL source when compiling nginx\n- `pagespeed_module`-\n- `passenger` - builds the passenger gem and configuration for \"`mod_passenger`\".\n- `set_misc` -\n- `syslog_module` - enables syslog support for nginx. This only works with source builds. See -\n- `upload_progress_module.rb` - builds the `upload_progress` module and enables it as a module when compiling nginx.\n\n## Resources\n\n### nginx_site\n\nEnable or disable a Server Block in `#{node['nginx']['dir']}/sites-available` by calling nxensite or nxdissite (introduced by this cookbook) to manage the symbolic link in `#{node['nginx']['dir']}/sites-enabled`.\n\n### Actions\n\n- `enable` - Enable the nginx site (default)\n- `disable` - Disable the nginx site\n\n### Properties:\n\n- `name` - (optional) Name of the site to enable. By default it's assumed that the name of the nginx_site resource is the site name, but this allows overriding that.\n- `template` - (optional) Path to the source for the `template` resource.\n- `cookbook` - (optional) The cookbook that contains the template source.\n- `variables` - (optional) Variables to be used with the `template` resource\n\n## Adding New Modules\n\nPreviously we'd add each possible module to this cookbook itself. That's not necessary using wrapper cookbooks and we'd prefer to not add any addition module recipes at this time. Instead in your nginx wrapper cookbook setup any necessary packages and then include the follow code to add the module to the list of modules to compile:\n\n```ruby\nnode.run_state['nginx_configure_flags'] =\n node.run_state['nginx_configure_flags'] | ['--with-SOMETHING', \"--with-SOME_OPT='things'\"]\n```\n\n## License & Authors\n\n- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))\n- Author:: Adam Jacob ([adam@chef.io](mailto:adam@chef.io))\n- Author:: AJ Christensen ([aj@chef.io](mailto:aj@chef.io))\n- Author:: Jamie Winsor ([jamie@vialstudios.com](mailto:jamie@vialstudios.com))\n- Author:: Mike Fiedler ([miketheman@gmail.com](mailto:miketheman@gmail.com))\n\n```text\nCopyright 2008-2016, Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","ubuntu":">= 0.0.0","suse":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","ohai":">= 4.1.0","yum-epel":">= 0.0.0","compat_resource":">= 12.16.3","zypper":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"chef_nginx":"Installs nginx package and sets up configuration with Debian apache style with sites-enabled/sites-available","chef_nginx::source":"Installs nginx from source and sets up configuration with Debian apache style with sites-enabled/sites-available"},"source_url":"https://github.com/chef-cookbooks/chef_nginx","issues_url":"https://github.com/chef-cookbooks/chef_nginx/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file +{"name":"chef_nginx","version":"6.1.1","description":"Installs and configures nginx","long_description":"# nginx Cookbook\n\n[![Cookbook](http://img.shields.io/cookbook/v/chef_nginx.svg)](https://supermarket.chef.io/cookbooks/chef_nginx) [![Build Status](https://travis-ci.org/chef-cookbooks/chef_nginx.svg?branch=master)](https://travis-ci.org/chef-cookbooks/chef_nginx)\n\nInstalls nginx from package OR source code and sets up configuration handling similar to Debian's Apache2 scripts.\n\n## nginx vs. chef_nginx\n\nThis cookbook is a fork from the 2.7.x branch of the [community nginx cookbook](https://github.com/miketheman/nginx).\n\nThis fork will be actively supported by Chef Software and we will continue to migrate the cookbook to a more resource driven model, with incremental changes following the SemVer model.\n\n## Requirements\n\n### Cookbooks\n\nThe following cookbooks are direct dependencies because they're used for common \"default\" functionality.\n\n- `build-essential` for source installations\n- `ohai` for setting up the ohai plugin\n- `compat_resource` for setting up the nginx.org repository on Chef 12.1 - 12.13\n- `yum-epel` for setting up the EPEL repository on RHEL platforms\n- `zypper` for setting up the nginx.org repository on Suse platforms\n\n### Platforms\n\nThe following platforms are supported and tested with Test Kitchen:\n\n- Ubuntu 14.04+\n- CentOS 6+\n- Debian 7+\n- openSUSE\n- FreeBSD\n\nOther Debian and RHEL family distributions are assumed to work.\n\n### Chef\n\n- Chef 12.1+\n\n## Attributes\n\nNode attributes for this cookbook are logically separated into different files. Some attributes are set only via a specific recipe.\n\n### chef_nginx::auth_request\n\nThese attributes are used in the `chef_nginx::auth_request` recipe.\n\n- `node['nginx']['auth_request']['url']` - The url to the auth_request module tar.gz file\n- `node['nginx']['auth_request']['checksum']` - The checksum of the auth_request module tar.gz file\n\n### chef_nginx::default\n\nGenerally used attributes. Some have platform specific values. See `attributes/default.rb`. \"The Config\" refers to \"nginx.conf\" the main config file.\n\n- `node['nginx']['dir']` - Location for nginx configuration.\n- `node['nginx']['conf_template']` - The `source` template to use when creating the `nginx.conf`.\n- `node['nginx']['conf_cookbook']` - The cookbook where `node['nginx']['conf_template']` resides.\n- `node['nginx']['log_dir']` - Location for nginx logs.\n- `node['nginx']['log_dir_perm']` - Permissions for nginx logs folder.\n- `node['nginx']['user']` - User that nginx will run as.\n- `node['nginx']['group']` - Group for nginx.\n- `node['nginx']['port']` - Port for nginx to listen on.\n- `node['nginx']['binary']` - Path to the nginx binary.\n- `node['nginx']['init_style']` - How to run nginx as a service when using `chef_nginx::source`. Values can be \"upstart\", \"systemd\", or \"init\". This attribute is not used in the `package` recipe because the package manager's init script style for the platform is assumed.\n- `node['nginx']['upstart']['foreground']` - Set this to true if you want upstart to run nginx in the foreground, set to false if you want upstart to detach and track the process via pid.\n- `node['nginx']['upstart']['runlevels']` - String of runlevels in the format '2345' which determines which runlevels nginx will start at when entering and stop at when leaving.\n- `node['nginx']['upstart']['respawn_limit']` - Respawn limit in upstart stanza format, count followed by space followed by interval in seconds.\n- `node['nginx']['keepalive']` - Whether to use `keepalive_timeout`, any value besides \"on\" will leave that option out of the config.\n- `node['nginx']['keepalive_requests']` - used for config value of `keepalive_requests`.\n- `node['nginx']['keepalive_timeout']` - used for config value of `keepalive_timeout`.\n- `node['nginx']['worker_processes']` - used for config value of `worker_processes`.\n- `node['nginx']['worker_connections']` - used for config value of `events { worker_connections }`\n- `node['nginx']['worker_rlimit_nofile']` - used for config value of `worker_rlimit_nofile`. Can replace any \"ulimit -n\" command. The value depend on your usage (cache or not) but must always be superior than worker_connections.\n- `node['nginx']['worker_shutdown_timeout']` - used for config value of `worker_shutdown_timeout`.\n- `node['nginx']['worker_connections']` - used for config value of `events { worker_connections }`\n- `node['nginx']['multi_accept']` - used for config value of `events { multi_accept }`. Try to accept() as many connections as possible. Disable by default.\n- `node['nginx']['event']` - used for config value of `events { use }`. Set the event-model. By default nginx looks for the most suitable method for your OS.\n- `node['nginx']['accept_mutex_delay']` - used for config value of `accept_mutex_delay`\n- `node['nginx']['server_tokens']` - used for config value of `server_tokens`.\n- `node['nginx']['server_names_hash_bucket_size']` - used for config value of `server_names_hash_bucket_size`.\n- `node['nginx']['disable_access_log']` - set to true to disable the general access log, may be useful on high traffic sites.\n- `node['nginx']['access_log_options']` - Set to a string of additional options to be appended to the access log directive\n- `node['nginx']['error_log_options']` - Set to a string of additional options to be appended to the error log directive\n- `node['nginx']['default_site_enabled']` - enable the default site\n- `node['nginx']['sendfile']` - Whether to use `sendfile`. Defaults to \"on\".\n- `node['nginx']['tcp_nopush']` - Whether to use `tcp_nopush`. Defaults to \"on\".\n- `node['nginx']['tcp_nodelay']` - Whether to use `tcp_nodelay`. Defaults to \"on\".\n- `node['nginx']['install_method']` - Whether nginx is installed from packages or from source.\n- `node['nginx']['types_hash_max_size']` - Used for the `types_hash_max_size` configuration directive.\n- `node['nginx']['types_hash_bucket_size']` - Used for the `types_hash_bucket_size` configuration directive.\n- `node['nginx']['proxy_read_timeout']` - defines a timeout (between two successive read operations) for reading a response from the proxied server.\n- `node['nginx']['client_body_buffer_size']` - used for config value of `client_body_buffer_size`.\n- `node['nginx']['client_max_body_size']` - specifies the maximum accepted body size of a client request, as indicated by the request header Content-Length.\n- `node['nginx']['repo_source']` - when installed from a package this attribute affects which yum repositories, if any, will be added before installing the nginx package. The default value of 'epel' will use the `yum-epel` cookbook, 'nginx' will use the `chef_nginx::repo` recipe, 'passenger' will use the 'chef_nginx::repo_passenger' recipe, and setting no value will not add any additional repositories.\n- `node['nginx']['sts_max_age']` - Enable Strict Transport Security for all apps (See: ). This attribute adds the following header: Strict-Transport-Security max-age=SECONDS to all incoming requests and takes an integer (in seconds) as its argument.\n- `node['nginx']['default']['modules']` - Array specifying which modules to enable via the conf-enabled config include function. Currently the only valid value is \"socketproxy\".\n- `node['nginx']['load_modules']` - Array of paths to modules to dynamically load on nginx startup using the `load_module` directive. Default is `[]`.\n\n#### authorized_ips module\n\n- `node['nginx']['remote_ip_var']` - The remote ip variable name to use.\n- `node['nginx']['authorized_ips']` - IPs authorized by the module\n\n#### gzip module\n\n- `node['nginx']['gzip']` - Whether to use gzip, can be \"on\" or \"off\"\n- `node['nginx']['gzip_http_version']` - used for config value of `gzip_http_version`.\n- `node['nginx']['gzip_comp_level']` - used for config value of `gzip_comp_level`.\n- `node['nginx']['gzip_proxied']` - used for config value of `gzip_proxied`.\n- `node['nginx']['gzip_vary']` - used for config value of `gzip_vary`.\n- `node['nginx']['gzip_buffers']` - used for config value of `gzip_buffers`.\n- `node['nginx']['gzip_types']` - used for config value of `gzip_types` - must be an Array.\n- `node['nginx']['gzip_min_length']` - used for config value of `gzip_min_length`.\n- `node['nginx']['gzip_disable']` - used for config value of `gzip_disable`.\n- `node['nginx']['gzip_static']` - used for config value of `gzip_static` (`http_gzip_static_module` must be enabled)\n\n#### Other configurations\n\n- `node['nginx']['extra_configs']` - a Hash of key/values to nginx configuration.\n\n### chef_nginx::devel\n\nThese attributes are used in the `chef_nginx::ngx_devel_module` recipe.\n\n- `node['nginx']['devel']['version']` - The version of the nginx devel module\n- `node['nginx']['devel']['url']` - The URL of the nginx devel module tar.gz file\n- `node['nginx']['devel']['checksum']` - The checksum of the nginx devel module tar.gz file\n\n### chef_nginx::echo\n\nThese attributes are used in the `chef_nginx::http_echo_module` recipe.\n\n- `node['nginx']['echo']['version']` - The version of `http_echo` you want (default: 0.59)\n- `node['nginx']['echo']['url']` - URL for the tarball.\n- `node['nginx']['echo']['checksum']` - Checksum of the tarball.\n\n### chef_nginx::geoip\n\nThese attributes are used in the `chef_nginx::http_geoip_module` recipe. Please note that the `country_dat_checksum` and `city_dat_checksum` are based on downloads from a datacenter in Fremont, CA, USA. You really should override these with checksums for the geo tarballs from your node location.\n\n**Note** The upstream, maxmind.com, may block access for repeated downloads of the data files. It is recommended that you download and host the data files, and change the URLs in the attributes.\n\n- `node['nginx']['geoip']['path']` - Location where to install the geoip libraries.\n- `node['nginx']['geoip']['enable_city']` - Whether to enable City data\n- `node['nginx']['geoip']['country_dat_url']` - Country data tarball URL\n- `node['nginx']['geoip']['country_dat_checksum']` - Country data tarball checksum\n- `node['nginx']['geoip']['city_dat_url']` - City data tarball URL\n- `node['nginx']['geoip']['city_dat_checksum']` - City data tarball checksum\n- `node['nginx']['geoip']['lib_version']` - Version of the GeoIP library to install\n- `node['nginx']['geoip']['lib_url']` - (Versioned) Tarball URL of the GeoIP library\n- `node['nginx']['geoip']['lib_checksum']` - Checksum of the GeoIP library tarball\n\n### chef_nginx::http_realip_module\n\nFrom: \n\n- `node['nginx']['realip']['header']` - Header to use for the RealIp Module; only accepts \"X-Forwarded-For\" or \"X-Real-IP\"\n- `node['nginx']['realip']['addresses']` - Addresses to use for the `http_realip` configuration.\n- `node['nginx']['realip']['real_ip_recursive']` - If recursive search is enabled, the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the request header field. Can be on \"on\" or \"off\" (default).\n\n### chef_nginx::openssl_source\n\nThese attributes are used in the `chef_nginx::openssl_source` recipe.\n\n- `node['nginx']['openssl_source']['version']` - The version of OpenSSL you want to download and use (default: 1.0.1t)\n- `node['nginx']['openssl_source']['url']` - The url for the OpenSSL source\n\n### chef_nginx::passenger\n\nThese attributes are used in the `chef_nginx::passenger` recipe.\n\n- `node['nginx']['passenger']['version']` - passenger gem version\n- `node['nginx']['passenger']['root']` - passenger gem root path\n- `node['nginx']['passenger']['install_rake']` - set to false if rake already present on system\n- `node['nginx']['passenger']['max_pool_size']` - maximum passenger pool size (default=10)\n- `node['nginx']['passenger']['ruby']` - Ruby path for Passenger to use (default=`$(which ruby)`)\n- `node['nginx']['passenger']['spawn_method']` - passenger spawn method to use (default=`smart-lv2`)\n- `node['nginx']['passenger']['buffer_response']` - turns on or off response buffering (default=`on`)\n- `node['nginx']['passenger']['max_pool_size']` - passenger maximum pool size (default=`6`)\n- `node['nginx']['passenger']['min_instances']` - minimum instances (default=`1`)\n- `node['nginx']['passenger']['max_instances_per_app']` - maximum instances per app (default=`0`)\n- `node['nginx']['passenger']['pool_idle_time']` - passenger pool idle time (default=`300`)\n- `node['nginx']['passenger']['max_requests']` - maximum requests (default=`0`)\n- `node['nginx']['passenger']['nodejs']` - Nodejs path for Passenger to use (default=nil)\n- `node['nginx']['passenger']['show_version_in_header']` - Show passenger version in HTTP headers (default=`on`)\n\nBasic configuration to use the official Phusion Passenger repositories:\n\n- `node['nginx']['repo_source']` - 'passenger'\n- `node['nginx']['package_name']` - 'nginx-extras'\n- `node['nginx']['passenger']['install_method']` - 'package'\n\n### chef_nginx::rate_limiting\n\n- `node['nginx']['enable_rate_limiting']` - set to true to enable rate limiting (`limit_req_zone` in nginx.conf)\n- `node['nginx']['rate_limiting_zone_name']` - sets the zone in `limit_req_zone`.\n- `node['nginx']['rate_limiting_backoff']` - sets the backoff time for `limit_req_zone`.\n- `node['nginx']['rate_limit']` - set the rate limit amount for `limit_req_zone`.\n\n### chef_nginx::repo\n\n- `node['nginx']['upstream_repository']` - the URL to use for the package repository resource; default is set based on platform type\n- `node['nginx']['repo_signing_key']` - The URL from which package signing/gpg key is retrieved\n\n### chef_nginx::socketproxy\n\nThese attributes are used in the `chef_nginx::socketproxy` recipe.\n\n- `node['nginx']['socketproxy']['root']` - The directory (on your server) where socketproxy apps are deployed.\n- `node['nginx']['socketproxy']['default_app']` - Static assets directory for requests to \"/\" that don't meet any proxy_pass filter requirements.\n- `node['nginx']['socketproxy']['apps']['app_name']['prepend_slash']` - Prepend a slash to requests to app \"app_name\" before sending them to the socketproxy socket.\n- `node['nginx']['socketproxy']['apps']['app_name']['context_name']` - URI (e.g. \"app_name\" in order to achieve \"\") at which to host the application \"app_name\"\n- `node['nginx']['socketproxy']['apps']['app_name']['subdir']` - Directory (under `node['nginx']['socketproxy']['root']`) in which to find the application.\n\n### chef_nginx::source\n\nThese attributes are used in the `chef_nginx::source` recipe. Some of them are dynamically modified during the run. See `attributes/source.rb` for default values.\n\n- `node['nginx']['source']['url']` - (versioned) URL for the nginx source code. By default this will use the version specified as `node['nginx']['version']`.\n- `node['nginx']['source']['prefix']` - (versioned) prefix for installing nginx from source\n- `node['nginx']['source']['conf_path']` - location of the main config file, in `node['nginx']['dir']` by default.\n- `node['nginx']['source']['modules']` - Array of modules that should be compiled into nginx by including their recipes in `chef_nginx::source`.\n- `node['nginx']['source']['default_configure_flags']` - The default flags passed to the configure script when building nginx.\n- `node['nginx']['configure_flags']` - Preserved for compatibility and dynamically generated from the `node['nginx']['source']['default_configure_flags']` in the `chef_nginx::source` recipe.\n- `node['nginx']['source']['use_existing_user']` - set to `true` if you do not want `chef_nginx::source` recipe to create system user with name `node['nginx']['user']`.\n\n### chef_nginx::status\n\nThese attributes are used in the `chef_nginx::http_stub_status_module` recipe.\n\n- `node['nginx']['status']['port']` - The port on which nginx will serve the status info (default: 8090)\n\n### chef_nginx::syslog\n\nThese attributes are used in the `chef_nginx::syslog_module` recipe.\n\n- `node['nginx']['syslog']['git_repo']` - The git repository url to use for the syslog patches.\n- `node['nginx']['syslog']['git_revision']` - The revision on the git repository to checkout.\n\n### chef_nginx::upload_progress\n\nThese attributes are used in the `chef_nginx::upload_progress_module` recipe.\n\n- `node['nginx']['upload_progress']['url']` - URL for the tarball.\n- `node['nginx']['upload_progress']['checksum']` - Checksum of the tarball.\n- `node['nginx']['upload_progress']['javascript_output']` - Output in javascript. Default is `true` for backwards compatibility.\n- `node['nginx']['upload_progress']['zone_name']` - Zone name which will be used to store the per-connection tracking information. Default is `proxied`.\n- `node['nginx']['upload_progress']['zone_size']` - Zone size in bytes. Default is `1m` (1 megabyte).\n\n## Resources\n\n### nginx_site\n\nEnable or disable a Server Block in `#{node['nginx']['dir']}/sites-available` by calling nxensite or nxdissite (introduced by this cookbook) to manage the symbolic link in `#{node['nginx']['dir']}/sites-enabled`.\n\n### Actions\n\n- `enable` - Enable the nginx site (default)\n- `disable` - Disable the nginx site\n\n### Properties:\n\n- `name` - (optional) Name of the site to enable. By default it's assumed that the name of the nginx_site resource is the site name, but this allows overriding that.\n- `template` - (optional) Path to the source for the `template` resource.\n- `variables` - (optional) Variables to be used with the `template` resource\n\n## Ohai Plugin\n\nThe `ohai_plugin` recipe includes an Ohai plugin. It will be automatically installed and activated, providing the following attributes via ohai, no matter how nginx is installed (source or package):\n\n- `node['nginx']['version']` - version of nginx\n- `node['nginx']['configure_arguments']` - options passed to `./configure` when nginx was built\n- `node['nginx']['prefix']` - installation prefix\n- `node['nginx']['conf_path']` - configuration file path\n\nIn the source recipe, it is used to determine whether control attributes for building nginx have changed.\n\n## Usage\n\nThis cookbook provides three distinct installation methods, all of which are controlled via attributes and executed using the chef_nginx::default recipe.\n\n### Package installation using the nginx.org repositories\n\nNginx provides repositories for RHEL, Debian/Ubuntu, and Suse platforms with up to date packages available on older distributions. Due to the age of many nginx packages shipping with distros we believe this is the ideal installation method. With no attributes set the nginx.org repositories will be added to your system and nginx will be installed via package. This provides a solid out of the box install for most users.\n\n### Package installation using distro repositories\n\nIf you prefer to use the packages included in your distro or to roll your own packages you'll want to set `node['nginx']['repo_source']` to `nil` or `distro` to skip the repository setup. The default recipe will still install nginx from packages, but you'll retain control over the package location.\n\n### Source installation to compile non-dynamic modules\n\nIf you need control over how nginx is built, or you need non-dynamic modules to be included you'll need to compile nginx from source. We highly recommend against using this method as it requires the installation of a full compilation toolchain and development dependencies on your nodes. Creating your own packages with nginx compiled as necessary is a preferred option. If that's not possible you can set `node['nginx']['install_method']` to `source` and provide a version in `node['nginx']['version']`.\n\n#### Specifying Modules to compile\n\nThe following recipes are used to build module support into nginx. To compile a module, add its recipe name to the array attribute `node['nginx']['source']['modules']`.\n\n- `ipv6.rb` - enables IPv6 support\n- `headers_more_module` -\n- `http_auth_request_module``\n- `http_echo_module.rb` - downloads the `http_echo_module` module and enables it as a module when compiling nginx.\n- `http_geoip_module.rb` - installs the GeoIP libraries and data files and enables the module for compilation.\n- `http_gzip_static_module.rb` - enables the module for compilation. Be sure to set `node['nginx']['gzip_static'] = 'yes'`.\n- `http_mp4_module` -\n- `http_perl_module.rb` - enables embedded Perl for compilation.\n- `http_realip_module.rb` - enables the module for compilation and creates the configuration.\n- `http_spdy_module` -\n- `http_ssl_module.rb` - enables SSL for compilation.\n- `http_stub_status_module.rb` - provides `nginx_status` configuration and enables the module for compilation.\n- `http_v2_module`\n- `ipv6` -\n- `naxsi_module` - enables the naxsi module for the web application firewall for nginx.\n- `ngx_devel_module` -\n- `ngx_lua_module` -\n- `openssl_source.rb` - downloads and uses custom OpenSSL source when compiling nginx\n- `pagespeed_module`-\n- `passenger` - builds the passenger gem and configuration for \"`mod_passenger`\".\n- `set_misc` -\n- `syslog_module` - enables syslog support for nginx. This only works with source builds. See -\n- `upload_progress_module.rb` - builds the `upload_progress` module and enables it as a module when compiling nginx.\n\n## Resources\n\n### nginx_site\n\nEnable or disable a Server Block in `#{node['nginx']['dir']}/sites-available` by calling nxensite or nxdissite (introduced by this cookbook) to manage the symbolic link in `#{node['nginx']['dir']}/sites-enabled`.\n\n### Actions\n\n- `enable` - Enable the nginx site (default)\n- `disable` - Disable the nginx site\n\n### Properties:\n\n- `name` - (optional) Name of the site to enable. By default it's assumed that the name of the nginx_site resource is the site name, but this allows overriding that.\n- `template` - (optional) Path to the source for the `template` resource.\n- `cookbook` - (optional) The cookbook that contains the template source.\n- `variables` - (optional) Variables to be used with the `template` resource\n\n## Adding New Modules\n\nPreviously we'd add each possible module to this cookbook itself. That's not necessary using wrapper cookbooks and we'd prefer to not add any addition module recipes at this time. Instead in your nginx wrapper cookbook setup any necessary packages and then include the follow code to add the module to the list of modules to compile:\n\n```ruby\nnode.run_state['nginx_configure_flags'] =\n node.run_state['nginx_configure_flags'] | ['--with-SOMETHING', \"--with-SOME_OPT='things'\"]\n```\n\n## License & Authors\n\n- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))\n- Author:: Adam Jacob ([adam@chef.io](mailto:adam@chef.io))\n- Author:: AJ Christensen ([aj@chef.io](mailto:aj@chef.io))\n- Author:: Jamie Winsor ([jamie@vialstudios.com](mailto:jamie@vialstudios.com))\n- Author:: Mike Fiedler ([miketheman@gmail.com](mailto:miketheman@gmail.com))\n\n```text\nCopyright 2008-2016, Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","ubuntu":">= 0.0.0","suse":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","ohai":">= 4.1.0","yum-epel":">= 0.0.0","compat_resource":">= 12.16.3","zypper":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"chef_nginx":"Installs nginx package and sets up configuration with Debian apache style with sites-enabled/sites-available","chef_nginx::source":"Installs nginx from source and sets up configuration with Debian apache style with sites-enabled/sites-available"},"source_url":"https://github.com/chef-cookbooks/chef_nginx","issues_url":"https://github.com/chef-cookbooks/chef_nginx/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/chef_nginx/recipes/commons_dir.rb b/cookbooks/chef_nginx/recipes/commons_dir.rb index 311020c..0a86d56 100644 --- a/cookbooks/chef_nginx/recipes/commons_dir.rb +++ b/cookbooks/chef_nginx/recipes/commons_dir.rb @@ -43,7 +43,7 @@ end end end -if !node['nginx']['default_site_enabled'] && platform_family?('rhel', 'fedora') +if !node['nginx']['default_site_enabled'] && platform_family?('rhel', 'fedora', 'amazon') %w(default.conf example_ssl.conf).each do |config| file "/etc/nginx/conf.d/#{config}" do action :delete diff --git a/cookbooks/chef_nginx/recipes/pagespeed_module.rb b/cookbooks/chef_nginx/recipes/pagespeed_module.rb index 150558b..bf2975b 100644 --- a/cookbooks/chef_nginx/recipes/pagespeed_module.rb +++ b/cookbooks/chef_nginx/recipes/pagespeed_module.rb @@ -22,7 +22,7 @@ remote_file psol_src_filepath do end package_array = value_for_platform_family( - %w(rhel) => node['nginx']['pagespeed']['packages']['rhel'], + %w(rhel amazon) => node['nginx']['pagespeed']['packages']['rhel'], %w(debian) => node['nginx']['pagespeed']['packages']['debian'] ) diff --git a/cookbooks/chef_nginx/recipes/passenger.rb b/cookbooks/chef_nginx/recipes/passenger.rb index 7dc27a5..dd7eda1 100644 --- a/cookbooks/chef_nginx/recipes/passenger.rb +++ b/cookbooks/chef_nginx/recipes/passenger.rb @@ -18,16 +18,12 @@ # packages = value_for_platform_family( - %w(rhel) => node['nginx']['passenger']['packages']['rhel'], + %w(rhel amazon) => node['nginx']['passenger']['packages']['rhel'], %w(fedora) => node['nginx']['passenger']['packages']['fedora'], %w(debian) => node['nginx']['passenger']['packages']['debian'] ) -unless packages.empty? - packages.each do |name| - package name - end -end +package packages unless packages.empty? gem_package 'rake' if node['nginx']['passenger']['install_rake'] diff --git a/cookbooks/chef_nginx/recipes/repo.rb b/cookbooks/chef_nginx/recipes/repo.rb index ee44e01..a396bfb 100644 --- a/cookbooks/chef_nginx/recipes/repo.rb +++ b/cookbooks/chef_nginx/recipes/repo.rb @@ -19,12 +19,12 @@ # case node['platform_family'] -when 'rhel' +when 'rhel', 'amazon' yum_repository 'nginx' do description 'Nginx.org Repository' baseurl node['nginx']['upstream_repository'] - gpgkey 'http://nginx.org/keys/nginx_signing.key' + gpgkey node['nginx']['repo_signing_key'] action :create end @@ -32,8 +32,8 @@ when 'suse' zypper_repo 'nginx' do repo_name 'Nginx.org Repository' - uri 'http://nginx.org/packages/sles/12' - key 'http://nginx.org/keys/nginx_signing.key' + uri node['nginx']['upstream_repository'] + key node['nginx']['repo_signing_key'] end when 'debian' @@ -43,7 +43,7 @@ when 'debian' distribution node['lsb']['codename'] components %w(nginx) deb_src true - key 'http://nginx.org/keys/nginx_signing.key' + key node['nginx']['repo_signing_key'] end else diff --git a/cookbooks/chef_nginx/recipes/source.rb b/cookbooks/chef_nginx/recipes/source.rb index 415fa1e..66f79bf 100644 --- a/cookbooks/chef_nginx/recipes/source.rb +++ b/cookbooks/chef_nginx/recipes/source.rb @@ -21,7 +21,7 @@ # limitations under the License. # -raise "#{node['platform']} is not a supported platform in the nginx::source recipe" unless platform_family?('rhel', 'fedora', 'debian', 'suse') +raise "#{node['platform']} is not a supported platform in the nginx::source recipe" unless platform_family?('rhel', 'amazon', 'fedora', 'debian', 'suse') node.normal['nginx']['binary'] = node['nginx']['source']['sbin_path'] node.normal['nginx']['daemon_disable'] = true @@ -42,7 +42,7 @@ src_filepath = "#{Chef::Config['file_cache_path']}/nginx-#{node['nginx']['source # install prereqs package value_for_platform_family( - %w(rhel fedora) => %w(pcre-devel openssl-devel tar), + %w(rhel fedora amazon) => %w(pcre-devel openssl-devel tar), %w(suse) => %w(pcre-devel libopenssl-devel tar), %w(debian) => %w(libpcre3 libpcre3-dev libssl-dev tar) ) diff --git a/cookbooks/chef_nginx/templates/default/modules/http_realip.conf.erb b/cookbooks/chef_nginx/templates/default/modules/http_realip.conf.erb index 3a5180c..032fc8c 100644 --- a/cookbooks/chef_nginx/templates/default/modules/http_realip.conf.erb +++ b/cookbooks/chef_nginx/templates/default/modules/http_realip.conf.erb @@ -2,6 +2,6 @@ set_real_ip_from <%= address %>; <% end -%> real_ip_header <%= node['nginx']['realip']['header'] %>; -<% if node['nginx']['version'].to_f >= 1.2 -%> +<% if NginxVersion.new(node['nginx']['version']) >= NginxVersion.new('1.2') -%> real_ip_recursive <%= node['nginx']['realip']['real_ip_recursive'] %>; <% end -%> diff --git a/cookbooks/compat_resource/CHANGELOG.md b/cookbooks/compat_resource/CHANGELOG.md index 592b3b8..7908196 100644 --- a/cookbooks/compat_resource/CHANGELOG.md +++ b/cookbooks/compat_resource/CHANGELOG.md @@ -2,6 +2,11 @@ This file is used to list changes made in each version of the compat_resource cookbook. +## 12.19.0 (2017-04-17) + +- Suppress warning already initialized constant +- Backport yum/apt changes from 12.19 + ## 12.16.2 (2016-11-09) - Sync chef-client changes from Chef 12.16.42 diff --git a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/support/yum_repo.erb b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/support/yum_repo.erb index 7d9a2d0..6f13255 100644 --- a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/support/yum_repo.erb +++ b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/support/yum_repo.erb @@ -4,8 +4,13 @@ [<%= @config.repositoryid %>] name=<%= @config.description %> <% if @config.baseurl %> -baseurl=<%= @config.baseurl %> -<% end %> +baseurl=<%= case @config.baseurl + when Array + @config.baseurl.join("\n") + else + @config.baseurl + end %> +<% end -%> <% if @config.cost %> cost=<%= @config.cost %> <% end %> @@ -24,7 +29,9 @@ exclude=<%= @config.exclude %> failovermethod=<%= @config.failovermethod %> <% end %> <% if @config.fastestmirror_enabled %> -fastestmirror_enabled=<%= @config.fastestmirror_enabled %> +fastestmirror_enabled=1 +<% else %> +fastestmirror_enabled=0 <% end %> <% if @config.gpgcheck %> gpgcheck=1 diff --git a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/yum_repository.rb b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/yum_repository.rb index bfe415e..51453d2 100644 --- a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/yum_repository.rb +++ b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/provider/yum_repository.rb @@ -89,16 +89,15 @@ class Chef < (defined?(::Chef) ? ::Chef : Object) end action :delete do - declare_resource(:file, "/etc/yum.repos.d/#{new_resource.repositoryid}.repo") do - action :delete - notifies :run, "execute[yum clean all #{new_resource.repositoryid}]", :immediately - notifies :create, "ruby_block[yum-cache-reload-#{new_resource.repositoryid}]", :immediately - end - + # clean the repo cache first declare_resource(:execute, "yum clean all #{new_resource.repositoryid}") do command "yum clean all --disablerepo=* --enablerepo=#{new_resource.repositoryid}" - only_if "yum repolist | grep -P '^#{new_resource.repositoryid}([ \t]|$)'" - action :nothing + only_if "yum repolist all | grep -P '^#{new_resource.repositoryid}([ \t]|$)'" + end + + declare_resource(:file, "/etc/yum.repos.d/#{new_resource.repositoryid}.repo") do + action :delete + notifies :create, "ruby_block[yum-cache-reload-#{new_resource.repositoryid}]", :immediately end declare_resource(:ruby_block, "yum-cache-reload-#{new_resource.repositoryid}") do diff --git a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_repository.rb b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_repository.rb index 1580fad..bedfd3e 100644 --- a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_repository.rb +++ b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_repository.rb @@ -54,7 +54,6 @@ class Chef < (defined?(::Chef) ? ::Chef : Object) property :cookbook, [String, nil, false], default: nil, desired_state: false, nillable: true, coerce: proc { |x| x ? x : nil } property :cache_rebuild, [TrueClass, FalseClass], default: true, desired_state: false - property :sensitive, [TrueClass, FalseClass], default: false, desired_state: false default_action :add allowed_actions :add, :remove diff --git a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_update.rb b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_update.rb index 31f5dc3..9acd9ae 100644 --- a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_update.rb +++ b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/apt_update.rb @@ -38,7 +38,7 @@ class Chef < (defined?(::Chef) ? ::Chef : Object) class Resource < (defined?(::Chef::Resource) ? ::Chef::Resource : Object) class AptUpdate < (defined?(::Chef::Resource::AptUpdate) ? ::Chef::Resource::AptUpdate : Chef::Resource) resource_name :apt_update - provides :apt_update, os: "linux" + provides :apt_update property :frequency, Integer, default: 86_400 diff --git a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/yum_repository.rb b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/yum_repository.rb index e733daa..97cf23a 100644 --- a/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/yum_repository.rb +++ b/cookbooks/compat_resource/files/lib/chef_compat/copied_from_chef/chef/resource/yum_repository.rb @@ -41,7 +41,7 @@ class Chef < (defined?(::Chef) ? ::Chef : Object) provides :yum_repository # http://linux.die.net/man/5/yum.conf - property :baseurl, String, regex: /.*/ + property :baseurl, [String, Array], regex: /.*/ property :cost, String, regex: /^\d+$/ property :clean_headers, [TrueClass, FalseClass], default: false # deprecated property :clean_metadata, [TrueClass, FalseClass], default: true @@ -74,7 +74,6 @@ class Chef < (defined?(::Chef) ? ::Chef : Object) property :repo_gpgcheck, [TrueClass, FalseClass] property :report_instanceid, [TrueClass, FalseClass] property :repositoryid, String, regex: /.*/, name_property: true - property :sensitive, [TrueClass, FalseClass], default: false property :skip_if_unavailable, [TrueClass, FalseClass] property :source, String, regex: /.*/ property :sslcacert, String, regex: /.*/ diff --git a/cookbooks/compat_resource/files/lib/chef_upstream_version.rb b/cookbooks/compat_resource/files/lib/chef_upstream_version.rb index 69c5f81..931e085 100644 --- a/cookbooks/compat_resource/files/lib/chef_upstream_version.rb +++ b/cookbooks/compat_resource/files/lib/chef_upstream_version.rb @@ -1,3 +1,3 @@ module ChefCompat - CHEF_UPSTREAM_VERSION="12.16.42" + CHEF_UPSTREAM_VERSION="12.16.42" unless defined? CHEF_UPSTREAM_VERSION end diff --git a/cookbooks/compat_resource/metadata.json b/cookbooks/compat_resource/metadata.json index af64b50..1df2f5d 100644 --- a/cookbooks/compat_resource/metadata.json +++ b/cookbooks/compat_resource/metadata.json @@ -1 +1 @@ -{"name":"compat_resource","version":"12.16.3","description":"Backports functionality introduced in the latest chef-client releases to any chef-client from 12.1 onwards","long_description":"# compat_resource cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/compat_resource.svg?branch=master)](https://travis-ci.org/chef-cookbooks/compat_resource) [![Cookbook Version](https://img.shields.io/cookbook/v/compat_resource.svg)](https://supermarket.chef.io/cookbooks/compat_resource)\n\nThis cookbook backports functionality introduced in the latest chef-client releases to any chef-client from 12.1 onwards. This includes [Custom Resource](https://docs.chef.io/custom_resources.html) functionality, notification improvements, as well as new resources added to core chef. It allows for the usage of these new resources in cookbooks without requiring the very latest Chef client release.\n\n## Backported functionality\n\n- [Custom Resources](https://docs.chef.io/custom_resources.html)\n- [apt_repository](https://docs.chef.io/resource_apt_repository.html)\n- [apt_update](https://docs.chef.io/resource_apt_update.html)\n- [systemd_unit](https://docs.chef.io/resource_systemd_unit.html)\n- [yum_repository](https://docs.chef.io/resource_yum_repository.html)\n- [:before notifications](https://docs.chef.io/resources.html#timers)\n\n## Requirements\n\n### Platforms\n\n- All platforms supported by Chef\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- none\n\n## Usage\n\nTo use this cookbook, put `depends 'compat_resource'` in the metadata.rb of your cookbook. Once this is done, you can use all the new custom resource features to define resources. It Just Works.\n\n## Custom Resources?\n\nCurious about how to use custom resources?\n\n- Docs: \n- Slides: \n\n## License & Authors\n\n- Author:: Lamont Granquist ([lamont@chef.io](mailto:lamont@chef.io))\n- Author:: John Keiser ([jkeiser@chef.io](mailto:jkeiser@chef.io))\n\n```text\nCopyright:: 2015-2016 Chef Software, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Lamont Granquist","maintainer_email":"lamont@chef.io","license":"Apache 2.0","platforms":{},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/compat_resource","issues_url":"https://github.com/chef-cookbooks/compat_resource/issues","chef_version":">= 12.1","ohai_version":{}} \ No newline at end of file +{"name":"compat_resource","version":"12.19.0","description":"Backports functionality introduced in the latest chef-client releases to any chef-client from 12.1 onwards","long_description":"# compat_resource cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/compat_resource.svg?branch=master)](https://travis-ci.org/chef-cookbooks/compat_resource) [![Cookbook Version](https://img.shields.io/cookbook/v/compat_resource.svg)](https://supermarket.chef.io/cookbooks/compat_resource)\n\nThis cookbook backports functionality introduced in the latest chef-client releases to any chef-client from 12.1 onwards. This includes [Custom Resource](https://docs.chef.io/custom_resources.html) functionality, notification improvements, as well as new resources added to core chef. It allows for the usage of these new resources in cookbooks without requiring the very latest Chef client release.\n\n## Backported functionality\n\n- [Custom Resources](https://docs.chef.io/custom_resources.html)\n- [apt_repository](https://docs.chef.io/resource_apt_repository.html)\n- [apt_update](https://docs.chef.io/resource_apt_update.html)\n- [systemd_unit](https://docs.chef.io/resource_systemd_unit.html)\n- [yum_repository](https://docs.chef.io/resource_yum_repository.html)\n- [:before notifications](https://docs.chef.io/resources.html#timers)\n\n## Requirements\n\n### Platforms\n\n- All platforms supported by Chef\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- none\n\n## Usage\n\nTo use this cookbook, put `depends 'compat_resource'` in the metadata.rb of your cookbook. Once this is done, you can use all the new custom resource features to define resources. It Just Works.\n\n## Custom Resources?\n\nCurious about how to use custom resources?\n\n- Docs: \n- Slides: \n\n## License & Authors\n\n- Author:: Lamont Granquist ([lamont@chef.io](mailto:lamont@chef.io))\n- Author:: John Keiser ([jkeiser@chef.io](mailto:jkeiser@chef.io))\n\n```text\nCopyright:: 2015-2016 Chef Software, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Lamont Granquist","maintainer_email":"lamont@chef.io","license":"Apache 2.0","platforms":{},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/compat_resource","issues_url":"https://github.com/chef-cookbooks/compat_resource/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/firewall/CHANGELOG.md b/cookbooks/firewall/CHANGELOG.md index e8dd996..e26b231 100644 --- a/cookbooks/firewall/CHANGELOG.md +++ b/cookbooks/firewall/CHANGELOG.md @@ -2,6 +2,12 @@ firewall Cookbook CHANGELOG ======================= This file is used to list changes made in each version of the firewall cookbook. +v2.6.2 (2017-06-01) +------------------- +* Incorrect file checking on Ubuntu, double file write (#173) +* Added testing on CentOS 6.9 +* Clarify metadata that we're not working on Amazon Linux (#172) + v2.6.1 (2017-04-21) ------------------- * Add recipe to disable firewall (#164) diff --git a/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb index c89320d..d6be1cd 100644 --- a/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb +++ b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu.rb @@ -43,7 +43,7 @@ class Chef rule_files = %w(rules.v4) rule_files << 'rules.v6' if ipv6_enabled?(new_resource) rule_files.each do |svc| - next unless ::File.exist?("/etc/iptables/#{svc}") + next if ::File.exist?("/etc/iptables/#{svc}") # must create empty file for service to start f = lookup_or_create_rulesfile(svc) diff --git a/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb index 8332be1..d2c3d74 100644 --- a/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb +++ b/cookbooks/firewall/libraries/provider_firewall_iptables_ubuntu1404.rb @@ -43,7 +43,7 @@ class Chef rule_files = %w(rules.v4) rule_files << 'rules.v6' if ipv6_enabled?(new_resource) rule_files.each do |svc| - next unless ::File.exist?("/etc/iptables/#{svc}") + next if ::File.exist?("/etc/iptables/#{svc}") # must create empty file for service to start f = lookup_or_create_rulesfile(svc) diff --git a/cookbooks/firewall/metadata.json b/cookbooks/firewall/metadata.json index 1a05794..0f1792c 100644 --- a/cookbooks/firewall/metadata.json +++ b/cookbooks/firewall/metadata.json @@ -1 +1 @@ -{"name":"firewall","version":"2.6.1","description":"Provides a set of primitives for managing firewalls and associated rules.","long_description":"firewall Cookbook\n=================\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/firewall.svg?branch=master)](http://travis-ci.org/chef-cookbooks/firewall)\n[![Cookbook Version](https://img.shields.io/cookbook/v/firewall.svg)](https://supermarket.chef.io/cookbooks/firewall)\n\nProvides a set of primitives for managing firewalls and associated rules.\n\nPLEASE NOTE - The resource/providers in this cookbook are under heavy development. An attempt is being made to keep the resource simple/stupid by starting with less sophisticated firewall implementations first and refactor/vet the resource definition with each successive provider.\n\nRequirements\n------------\n**Chef 12.4.x+** is required. We are currently testing against 12.8.1. If you need Chef 11 support, please try pinning back to a version less than 2.0, e.g.:\n```\ndepends 'firewall', '< 2.0'\n```\n\n### Supported firewalls and platforms\n* UFW - Ubuntu, Debian\n* IPTables - Red Hat & CentOS, Ubuntu\n* FirewallD - Red Hat & CentOS >= 7.0 (IPv4 only support, [needs contributions/testing](https://github.com/chef-cookbooks/firewall/issues/86))\n* Windows Advanced Firewall - 2012 R2\n\nTested on:\n* Ubuntu 12.04, 14.04, 16.04 with iptables, ufw\n* Debian 7.8, 8.1 with ufw\n* CentOS 5.11, 6.7 with iptables\n* CentOS 7.1 with firewalld\n* Windows Server 2012r2 with Windows Advanced Firewall\n\nBy default, Ubuntu chooses ufw. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['ubuntu_iptables'] = true\n```\n\nBy default, Red Hat & CentOS >= 7.0 chooses firewalld. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['redhat7_iptables'] = true\n```\n\n# Considerations that apply to all firewall providers and resources\n\nThis cookbook comes with two resources, firewall and firewall rule. The typical usage scenario is as follows:\n\n- run the `:install` action on the `firewall` resource named 'default', which installs appropriate packages and configures services to start on boot and starts them\n\n- run the `:create` action on every `firewall_rule` resource, which adds to the list of rules that should be configured on the firewall. `firewall_rule` then automatically sends a delayed notification to the `firewall['default']` resource to run the `:restart` action.\n\n- run the delayed notification with action `:restart` on the `firewall` resource. if any rules are different than the last run, the provider will update the current state of the firewall rules to match the expected rules.\n\nThere is a fundamental mismatch between the idea of a chef action and the action that should be taken on a firewall rule. For this reason, the chef action for a firewall_rule may be `:nothing` (the rule should not be present in the firewall) or `:create` (the rule should be present in the firewall), but the action taken on a packet in a firewall (`DROP`, `ACCEPT`, etc) is denoted as a `command` parameter on the `firewall_rule` resource.\n\n# iptables considerations\n\nIf you need to use a table other than `*filter`, the best way to do so is like so:\n```\nnode.default['firewall']['iptables']['defaults'][:ruleset] = {\n '*filter' => 1,\n ':INPUT DROP' => 2,\n ':FORWARD DROP' => 3,\n ':OUTPUT ACCEPT_FILTER' => 4,\n 'COMMIT_FILTER' => 100,\n '*nat' => 101,\n ':PREROUTING DROP' => 102,\n ':POSTROUTING DROP' => 103,\n ':OUTPUT ACCEPT_NAT' => 104,\n 'COMMIT_NAT' => 200\n}\n```\n\nNote -- in order to support multiple hash keys containing the same rule, anything found after the underscore will be stripped for: `:OUTPUT :INPUT :POSTROUTING :PREROUTING COMMIT`. This allows an example like the above to be reduced to just repeated lines of `COMMIT` and `:OUTPUT ACCEPT` while still avoiding duplication of other things.\n\nThen it's trivial to add additional rules to the `*nat` table using the raw parameter:\n```\nfirewall_rule \"postroute\" do\n raw \"-A POSTROUTING -o eth1 -p tcp -d 172.28.128.21 -j SNAT --to-source 172.28.128.6\"\n position 150\nend\n```\n\nNote that any line starting with `COMMIT` will become just `COMMIT`, as hash\nkeys must be unique but we need multiple commit lines.\n\n# Recipes\n\n### default\nThe default recipe creates a firewall resource with action install.\n\n### disable_firewall\nUsed to disable platform specific firewall. Many clouds have their own firewall configured outside of the OS instance such as AWS Security Groups.\n\n# Attributes\n\n* `default['firewall']['allow_ssh'] = false`, set true to open port 22 for SSH when the default recipe runs\n* `default['firewall']['allow_mosh'] = false`, set to true to open UDP ports 60000 - 61000 for [Mosh][0] when the default recipe runs\n* `default['firewall']['allow_winrm'] = false`, set true to open port 5989 for WinRM when the default recipe runs\n* `default['firewall']['allow_loopback'] = false`, set to true to allow all traffic on the loopback interface\n* `default['firewall']['allow_icmp'] = false`, set true to allow icmp protocol on supported OSes (note: ufw and windows implementations don't support this)\n\n* `default['firewall']['ubuntu_iptables'] = false`, set to true to use iptables on Ubuntu / Debian when using the default recipe\n* `default['firewall']['redhat7_iptables'] = false`, set to true to use iptables on Red Hat / CentOS 7 when using the default recipe\n\n* `default['firewall']['ufw']['defaults']` hash for template `/etc/default/ufw`\n* `default['firewall']['iptables']['defaults']` hash for default policies for 'filter' table's chains`\n\n* `default['firewall']['windows']['defaults']` hash to define inbound / outbound firewall policy on Windows platform\n\n* `default['firewall']['allow_established'] = true`, set to false if you don't want a related/established default rule on iptables\n* `default['firewall']['ipv6_enabled'] = true`, set to false if you don't want IPv6 related/established default rule on iptables (this enables ICMPv6, which is required for much of IPv6 communication)\n\n* `default['firewall']['firewalld']['permanent'] = false`, set to true if you want firewalld rules to be added with `--permanent` so they survive a reboot. This will be changed to `true` by default in a future major version release.\n\n# Resources\n\n### firewall\n\n***NB***: The name 'default' of this resource is important as it is used for firewall_rule providers to locate the firewall resource. If you change it, you must also supply the same value to any firewall_rule resources using the `firewall_name` parameter.\n\n#### Actions\n- `:install` (*default action*): Install and Enable the firewall. This will ensure the appropriate packages are installed and that any services have been started.\n- `:disable`: Disable the firewall. Drop any rules and put the node in an unprotected state. Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:flush`: Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:save`: Ensure all rules are added permanently under firewalld using `--permanent`. Not supported on ufw, iptables. You must notify this action at the end of the chef run if you want permanent firewalld rules (they are not persistent by default).\n\n#### Parameters\n\n- `disabled` (default to `false`): If set to true, all actions will no-op on this resource. This is a way to prevent included cookbooks from configuring a firewall.\n- `ipv6_enabled` (default to `true`): If set to false, firewall will not perform any ipv6 related work. Currently only supported in iptables.\n- `log_level`: UFW only. Level of verbosity the firewall should log at. valid values are: :low, :medium, :high, :full, :off. default is :low.\n- `rules`: This is used internally for firewall_rule resources to append their rules. You should NOT touch this value unless you plan to supply an entire firewall ruleset at once, and skip using firewall_rule resources.\n- `disabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be disabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:public.`\n- `enabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be enabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:drop.`\n- `package_options`: Used to pass options to the package install of firewall\n\n#### Examples\n\n```ruby\n# all defaults\nfirewall 'default'\n\n# enable platform default firewall\nfirewall 'default' do\n action :install\nend\n\n# increase logging past default of 'low'\nfirewall 'default' do\n log_level :high\n action :install\nend\n```\n\n### firewall_rule\n\n#### Actions\n- `:create` (_default action_): If a firewall_rule runs this action, the rule will be recorded in a chef resource's internal state, and applied when providers automatically notify the firewall resource with action `:reload`. The notification happens automatically.\n\n#### Parameters\n\n- `firewall_name`: the matching firewall resource that this rule applies to. Default value: `default`\n\n- `raw`: Used to pass an entire rule as a string, omitting all other parameters. This line will be directly loaded by `iptables-restore`, fed directly into `ufw` on the command line, or run using `firewall-cmd`.\n\n- `description` (_default: same as rule name_): Used to provide a comment that will be included when adding the firewall rule.\n\n- `position` (_default: 50_): **relative** position to insert rule at. Position may be any integer between 0 < n < 100 (exclusive), and more than one rule may specify the same position.\n\n- `command`: What action to take on a particular packet\n\n - `:allow` (_default action_): the rule should allow matching packets\n - `:deny`: the rule should deny matching packets\n - `:reject`: the rule should reject matching packets\n - `:masqerade`: Masquerade the matching packets\n - `:redirect`: Redirect the matching packets\n - `:log`: Configure logging\n\n- `stateful`: a symbol or array of symbols, such as ``[:related, :established]` that will be passed to the state module in iptables or firewalld.\n\n- `protocol`: `:tcp` (_default_), `:udp`, `:icmp`, `:none` or protocol number. Using protocol numbers is not supported using the ufw provider (default for debian/ubuntu systems).\n\n- `direction`: For ufw, direction of the rule. valid values are: `:in` (_default_), `:out`, `:pre`, `:post`.\n\n- `source` (_Default is `0.0.0.0/0` or `Anywhere`_): source ip address or subnet to filter.\n\n- `source_port` (_Default is nil_): source port for filtering packets.\n\n- `destination`: ip address or subnet to filter on packet destination, must be a valid IP\n\n- `port` or `dest_port`: target port number (ie. 22 to allow inbound SSH), or an array of incoming port numbers (ie. [80,443] to allow inbound HTTP & HTTPS).\n\n NOTE: `protocol` attribute is required with multiple ports, or a range of incoming port numbers (ie. 60000..61000 to allow inbound mobile-shell. NOTE: `protocol`, or an attribute is required with a range of ports.\n\n- `interface`: (source) interface to apply rule (ie. `eth0`).\n\n- `dest_interface`: interface where packets may be destined to go\n\n- `redirect_port`: redirected port for rules with command `:redirect`\n\n- `logging`: may be added to enable logging for a particular rule. valid values are: `:connections`, `:packets`. In the ufw provider, `:connections` logs new connections while `:packets` logs all packets.\n\n#### Examples\n\n```ruby\n# open standard ssh port\nfirewall_rule 'ssh' do\n port 22\n command :allow\nend\n\n# open standard http port to tcp traffic only; insert as first rule\nfirewall_rule 'http' do\n port 80\n protocol :tcp\n position 1\n command :allow\nend\n\n# restrict port 13579 to 10.0.111.0/24 on eth0\nfirewall_rule 'myapplication' do\n port 13579\n source '10.0.111.0/24'\n direction :in\n interface 'eth0'\n command :allow\nend\n\n# specify a protocol number (supported on centos/redhat)\nfirewall_rule 'vrrp' do\n protocol 112\n command :allow\nend\n\n# use the iptables provider to specify protocol number on debian/ubuntu\nfirewall_rule 'vrrp' do\n provider Chef::Provider::FirewallRuleIptables\n protocol 112\n command :allow\nend\n\n# can use :raw command with UFW provider for VRRP\nfirewall_rule \"VRRP\" do\n command :allow\n raw \"allow to 224.0.0.18\"\nend\n\n# open UDP ports 60000..61000 for mobile shell (mosh.mit.edu), note\n# that the protocol attribute is required when using port_range\nfirewall_rule 'mosh' do\n protocol :udp\n port 60000..61000\n command :allow\nend\n\n# open multiple ports for http/https, note that the protocol\n# attribute is required when using ports\nfirewall_rule 'http/https' do\n protocol :tcp\n port [80, 443]\n command :allow\nend\n\nfirewall 'default' do\n enabled false\n action :nothing\nend\n```\n\n#### Providers\n\n- See `libraries/z_provider_mapping.rb` for a full list of providers for each platform and version.\n\nDifferent providers will determine the current state of the rules differently -- parsing the output of a command, maintaining the state in a file, or some other way. If the firewall is adjusted from outside of chef (non-idempotent), it's possible that chef may be caught unaware of the current state of the firewall. The best workaround is to add a `:flush` action to the firewall resource as early as possible in the chef run, if you plan to modify the firewall state outside of chef.\n\n# Troubleshooting\n\nTo figure out what the position values are for current rules, print the hash that contains the weights:\n```\nrequire pp\ndefault_firewall = resources(:firewall, 'default')\npp default_firewall.rules\n```\n\n# Development\nThis section details \"quick development\" steps. For a detailed explanation, see [[Contributing.md]].\n\n1. Clone this repository from GitHub:\n\n $ git clone git@github.com:chef-cookbooks/firewall.git\n\n2. Create a git branch\n\n $ git checkout -b my_bug_fix\n\n3. Install dependencies:\n\n $ bundle install\n\n4. Make your changes/patches/fixes, committing appropiately\n5. **Write tests**\n6. Run the tests:\n - `bundle exec foodcritic -f any .`\n - `bundle exec rspec`\n - `bundle exec rubocop`\n - `bundle exec kitchen test`\n\n In detail:\n - Foodcritic will catch any Chef-specific style errors\n - RSpec will run the unit tests\n - Rubocop will check for Ruby-specific style errors\n - Test Kitchen will run and converge the recipes\n\n\n# License & Authors\n\n- Author:: Seth Chisamore ()\n- Author:: Ronald Doorn ()\n- Author:: Martin Smith ()\n- Author:: Sander van Harmelen ()\n\n```text\nCopyright:: 2011-2015, Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[0]: https://mosh.mit.edu/\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0"},"dependencies":{"chef-sugar":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/firewall","issues_url":"https://github.com/chef-cookbooks/firewall/issues","chef_version":[[">= 12.5"]],"ohai_version":[]} \ No newline at end of file +{"name":"firewall","version":"2.6.2","description":"Provides a set of primitives for managing firewalls and associated rules.","long_description":"firewall Cookbook\n=================\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/firewall.svg?branch=master)](http://travis-ci.org/chef-cookbooks/firewall)\n[![Cookbook Version](https://img.shields.io/cookbook/v/firewall.svg)](https://supermarket.chef.io/cookbooks/firewall)\n\nProvides a set of primitives for managing firewalls and associated rules.\n\nPLEASE NOTE - The resource/providers in this cookbook are under heavy development. An attempt is being made to keep the resource simple/stupid by starting with less sophisticated firewall implementations first and refactor/vet the resource definition with each successive provider.\n\nRequirements\n------------\n**Chef 12.4.x+** is required. We are currently testing against 12.8.1. If you need Chef 11 support, please try pinning back to a version less than 2.0, e.g.:\n```\ndepends 'firewall', '< 2.0'\n```\n\n### Supported firewalls and platforms\n* UFW - Ubuntu, Debian\n* IPTables - Red Hat & CentOS, Ubuntu\n* FirewallD - Red Hat & CentOS >= 7.0 (IPv4 only support, [needs contributions/testing](https://github.com/chef-cookbooks/firewall/issues/86))\n* Windows Advanced Firewall - 2012 R2\n\nTested on:\n* Ubuntu 12.04, 14.04, 16.04 with iptables, ufw\n* Debian 7.8, 8.1 with ufw\n* CentOS 5.11, 6.7 with iptables\n* CentOS 7.1 with firewalld\n* Windows Server 2012r2 with Windows Advanced Firewall\n\nBy default, Ubuntu chooses ufw. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['ubuntu_iptables'] = true\n```\n\nBy default, Red Hat & CentOS >= 7.0 chooses firewalld. To switch to iptables, set this in an attribute file:\n```\ndefault['firewall']['redhat7_iptables'] = true\n```\n\n# Considerations that apply to all firewall providers and resources\n\nThis cookbook comes with two resources, firewall and firewall rule. The typical usage scenario is as follows:\n\n- run the `:install` action on the `firewall` resource named 'default', which installs appropriate packages and configures services to start on boot and starts them\n\n- run the `:create` action on every `firewall_rule` resource, which adds to the list of rules that should be configured on the firewall. `firewall_rule` then automatically sends a delayed notification to the `firewall['default']` resource to run the `:restart` action.\n\n- run the delayed notification with action `:restart` on the `firewall` resource. if any rules are different than the last run, the provider will update the current state of the firewall rules to match the expected rules.\n\nThere is a fundamental mismatch between the idea of a chef action and the action that should be taken on a firewall rule. For this reason, the chef action for a firewall_rule may be `:nothing` (the rule should not be present in the firewall) or `:create` (the rule should be present in the firewall), but the action taken on a packet in a firewall (`DROP`, `ACCEPT`, etc) is denoted as a `command` parameter on the `firewall_rule` resource.\n\n# iptables considerations\n\nIf you need to use a table other than `*filter`, the best way to do so is like so:\n```\nnode.default['firewall']['iptables']['defaults'][:ruleset] = {\n '*filter' => 1,\n ':INPUT DROP' => 2,\n ':FORWARD DROP' => 3,\n ':OUTPUT ACCEPT_FILTER' => 4,\n 'COMMIT_FILTER' => 100,\n '*nat' => 101,\n ':PREROUTING DROP' => 102,\n ':POSTROUTING DROP' => 103,\n ':OUTPUT ACCEPT_NAT' => 104,\n 'COMMIT_NAT' => 200\n}\n```\n\nNote -- in order to support multiple hash keys containing the same rule, anything found after the underscore will be stripped for: `:OUTPUT :INPUT :POSTROUTING :PREROUTING COMMIT`. This allows an example like the above to be reduced to just repeated lines of `COMMIT` and `:OUTPUT ACCEPT` while still avoiding duplication of other things.\n\nThen it's trivial to add additional rules to the `*nat` table using the raw parameter:\n```\nfirewall_rule \"postroute\" do\n raw \"-A POSTROUTING -o eth1 -p tcp -d 172.28.128.21 -j SNAT --to-source 172.28.128.6\"\n position 150\nend\n```\n\nNote that any line starting with `COMMIT` will become just `COMMIT`, as hash\nkeys must be unique but we need multiple commit lines.\n\n# Recipes\n\n### default\nThe default recipe creates a firewall resource with action install.\n\n### disable_firewall\nUsed to disable platform specific firewall. Many clouds have their own firewall configured outside of the OS instance such as AWS Security Groups.\n\n# Attributes\n\n* `default['firewall']['allow_ssh'] = false`, set true to open port 22 for SSH when the default recipe runs\n* `default['firewall']['allow_mosh'] = false`, set to true to open UDP ports 60000 - 61000 for [Mosh][0] when the default recipe runs\n* `default['firewall']['allow_winrm'] = false`, set true to open port 5989 for WinRM when the default recipe runs\n* `default['firewall']['allow_loopback'] = false`, set to true to allow all traffic on the loopback interface\n* `default['firewall']['allow_icmp'] = false`, set true to allow icmp protocol on supported OSes (note: ufw and windows implementations don't support this)\n\n* `default['firewall']['ubuntu_iptables'] = false`, set to true to use iptables on Ubuntu / Debian when using the default recipe\n* `default['firewall']['redhat7_iptables'] = false`, set to true to use iptables on Red Hat / CentOS 7 when using the default recipe\n\n* `default['firewall']['ufw']['defaults']` hash for template `/etc/default/ufw`\n* `default['firewall']['iptables']['defaults']` hash for default policies for 'filter' table's chains`\n\n* `default['firewall']['windows']['defaults']` hash to define inbound / outbound firewall policy on Windows platform\n\n* `default['firewall']['allow_established'] = true`, set to false if you don't want a related/established default rule on iptables\n* `default['firewall']['ipv6_enabled'] = true`, set to false if you don't want IPv6 related/established default rule on iptables (this enables ICMPv6, which is required for much of IPv6 communication)\n\n* `default['firewall']['firewalld']['permanent'] = false`, set to true if you want firewalld rules to be added with `--permanent` so they survive a reboot. This will be changed to `true` by default in a future major version release.\n\n# Resources\n\n### firewall\n\n***NB***: The name 'default' of this resource is important as it is used for firewall_rule providers to locate the firewall resource. If you change it, you must also supply the same value to any firewall_rule resources using the `firewall_name` parameter.\n\n#### Actions\n- `:install` (*default action*): Install and Enable the firewall. This will ensure the appropriate packages are installed and that any services have been started.\n- `:disable`: Disable the firewall. Drop any rules and put the node in an unprotected state. Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:flush`: Flush all current rules. Also erase any internal state used to detect when rules should be applied.\n- `:save`: Ensure all rules are added permanently under firewalld using `--permanent`. Not supported on ufw, iptables. You must notify this action at the end of the chef run if you want permanent firewalld rules (they are not persistent by default).\n\n#### Parameters\n\n- `disabled` (default to `false`): If set to true, all actions will no-op on this resource. This is a way to prevent included cookbooks from configuring a firewall.\n- `ipv6_enabled` (default to `true`): If set to false, firewall will not perform any ipv6 related work. Currently only supported in iptables.\n- `log_level`: UFW only. Level of verbosity the firewall should log at. valid values are: :low, :medium, :high, :full, :off. default is :low.\n- `rules`: This is used internally for firewall_rule resources to append their rules. You should NOT touch this value unless you plan to supply an entire firewall ruleset at once, and skip using firewall_rule resources.\n- `disabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be disabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:public.`\n- `enabled_zone` (firewalld only): The zone to set on firewalld when the firewall should be enabled. Can be any string in symbol form, e.g. :public, :drop, etc. Defaults to `:drop.`\n- `package_options`: Used to pass options to the package install of firewall\n\n#### Examples\n\n```ruby\n# all defaults\nfirewall 'default'\n\n# enable platform default firewall\nfirewall 'default' do\n action :install\nend\n\n# increase logging past default of 'low'\nfirewall 'default' do\n log_level :high\n action :install\nend\n```\n\n### firewall_rule\n\n#### Actions\n- `:create` (_default action_): If a firewall_rule runs this action, the rule will be recorded in a chef resource's internal state, and applied when providers automatically notify the firewall resource with action `:reload`. The notification happens automatically.\n\n#### Parameters\n\n- `firewall_name`: the matching firewall resource that this rule applies to. Default value: `default`\n\n- `raw`: Used to pass an entire rule as a string, omitting all other parameters. This line will be directly loaded by `iptables-restore`, fed directly into `ufw` on the command line, or run using `firewall-cmd`.\n\n- `description` (_default: same as rule name_): Used to provide a comment that will be included when adding the firewall rule.\n\n- `position` (_default: 50_): **relative** position to insert rule at. Position may be any integer between 0 < n < 100 (exclusive), and more than one rule may specify the same position.\n\n- `command`: What action to take on a particular packet\n\n - `:allow` (_default action_): the rule should allow matching packets\n - `:deny`: the rule should deny matching packets\n - `:reject`: the rule should reject matching packets\n - `:masqerade`: Masquerade the matching packets\n - `:redirect`: Redirect the matching packets\n - `:log`: Configure logging\n\n- `stateful`: a symbol or array of symbols, such as ``[:related, :established]` that will be passed to the state module in iptables or firewalld.\n\n- `protocol`: `:tcp` (_default_), `:udp`, `:icmp`, `:none` or protocol number. Using protocol numbers is not supported using the ufw provider (default for debian/ubuntu systems).\n\n- `direction`: For ufw, direction of the rule. valid values are: `:in` (_default_), `:out`, `:pre`, `:post`.\n\n- `source` (_Default is `0.0.0.0/0` or `Anywhere`_): source ip address or subnet to filter.\n\n- `source_port` (_Default is nil_): source port for filtering packets.\n\n- `destination`: ip address or subnet to filter on packet destination, must be a valid IP\n\n- `port` or `dest_port`: target port number (ie. 22 to allow inbound SSH), or an array of incoming port numbers (ie. [80,443] to allow inbound HTTP & HTTPS).\n\n NOTE: `protocol` attribute is required with multiple ports, or a range of incoming port numbers (ie. 60000..61000 to allow inbound mobile-shell. NOTE: `protocol`, or an attribute is required with a range of ports.\n\n- `interface`: (source) interface to apply rule (ie. `eth0`).\n\n- `dest_interface`: interface where packets may be destined to go\n\n- `redirect_port`: redirected port for rules with command `:redirect`\n\n- `logging`: may be added to enable logging for a particular rule. valid values are: `:connections`, `:packets`. In the ufw provider, `:connections` logs new connections while `:packets` logs all packets.\n\n#### Examples\n\n```ruby\n# open standard ssh port\nfirewall_rule 'ssh' do\n port 22\n command :allow\nend\n\n# open standard http port to tcp traffic only; insert as first rule\nfirewall_rule 'http' do\n port 80\n protocol :tcp\n position 1\n command :allow\nend\n\n# restrict port 13579 to 10.0.111.0/24 on eth0\nfirewall_rule 'myapplication' do\n port 13579\n source '10.0.111.0/24'\n direction :in\n interface 'eth0'\n command :allow\nend\n\n# specify a protocol number (supported on centos/redhat)\nfirewall_rule 'vrrp' do\n protocol 112\n command :allow\nend\n\n# use the iptables provider to specify protocol number on debian/ubuntu\nfirewall_rule 'vrrp' do\n provider Chef::Provider::FirewallRuleIptables\n protocol 112\n command :allow\nend\n\n# can use :raw command with UFW provider for VRRP\nfirewall_rule \"VRRP\" do\n command :allow\n raw \"allow to 224.0.0.18\"\nend\n\n# open UDP ports 60000..61000 for mobile shell (mosh.mit.edu), note\n# that the protocol attribute is required when using port_range\nfirewall_rule 'mosh' do\n protocol :udp\n port 60000..61000\n command :allow\nend\n\n# open multiple ports for http/https, note that the protocol\n# attribute is required when using ports\nfirewall_rule 'http/https' do\n protocol :tcp\n port [80, 443]\n command :allow\nend\n\nfirewall 'default' do\n enabled false\n action :nothing\nend\n```\n\n#### Providers\n\n- See `libraries/z_provider_mapping.rb` for a full list of providers for each platform and version.\n\nDifferent providers will determine the current state of the rules differently -- parsing the output of a command, maintaining the state in a file, or some other way. If the firewall is adjusted from outside of chef (non-idempotent), it's possible that chef may be caught unaware of the current state of the firewall. The best workaround is to add a `:flush` action to the firewall resource as early as possible in the chef run, if you plan to modify the firewall state outside of chef.\n\n# Troubleshooting\n\nTo figure out what the position values are for current rules, print the hash that contains the weights:\n```\nrequire pp\ndefault_firewall = resources(:firewall, 'default')\npp default_firewall.rules\n```\n\n# Development\nThis section details \"quick development\" steps. For a detailed explanation, see [[Contributing.md]].\n\n1. Clone this repository from GitHub:\n\n $ git clone git@github.com:chef-cookbooks/firewall.git\n\n2. Create a git branch\n\n $ git checkout -b my_bug_fix\n\n3. Install dependencies:\n\n $ bundle install\n\n4. Make your changes/patches/fixes, committing appropiately\n5. **Write tests**\n6. Run the tests:\n - `bundle exec foodcritic -f any .`\n - `bundle exec rspec`\n - `bundle exec rubocop`\n - `bundle exec kitchen test`\n\n In detail:\n - Foodcritic will catch any Chef-specific style errors\n - RSpec will run the unit tests\n - Rubocop will check for Ruby-specific style errors\n - Test Kitchen will run and converge the recipes\n\n\n# License & Authors\n\n- Author:: Seth Chisamore ()\n- Author:: Ronald Doorn ()\n- Author:: Martin Smith ()\n- Author:: Sander van Harmelen ()\n\n```text\nCopyright:: 2011-2015, Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\n[0]: https://mosh.mit.edu/\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"centos":">= 0.0.0","debian":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0"},"dependencies":{"chef-sugar":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/firewall","issues_url":"https://github.com/chef-cookbooks/firewall/issues","chef_version":[[">= 12.5"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/hostname/.gitignore b/cookbooks/hostname/.gitignore index 771929b..02e8bbc 100644 --- a/cookbooks/hostname/.gitignore +++ b/cookbooks/hostname/.gitignore @@ -13,3 +13,4 @@ Gemfile.lock \#*# bin/* metadata.json +Gemfile.lock diff --git a/cookbooks/hostname/.kitchen.yml b/cookbooks/hostname/.kitchen.yml index 8bda6a3..a1bca39 100644 --- a/cookbooks/hostname/.kitchen.yml +++ b/cookbooks/hostname/.kitchen.yml @@ -4,58 +4,31 @@ driver_config: require_chef_omnibus: true platforms: -- name: ubuntu-14.04 - driver_config: - box: opscode_ubuntu-14.04_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-14.04_chef-provisionerless.box -- name: ubuntu-12.04 - driver_config: - box: opscode_ubuntu-12.04_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-12.04_chef-provisionerless.box -- name: ubuntu-10.04 - driver_config: - box: opscode_ubuntu-10.04_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-10.04_chef-provisionerless.box -- name: debian-6 - driver_config: - box: opscode_debian-6.0.8_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_debian-6.0.8_chef-provisionerless.box -- name: debian-7 - driver_config: - box: opscode_debian-7.2.0_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_debian-7.2.0_chef-provisionerless.box -- name: centos-6.4 - driver_config: - box: opscode_centos-6.4_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.4_chef-provisionerless.box -#- name: freebsd-9.2 -# driver_config: -# box: opscode_freebsd-9.2_provisionerless -# box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_freebsd-9.2_chef-provisionerless.box -- name: freebsd-10 - driver_config: - box: opscode_freebsd-10.0_provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_freebsd-10.0_chef-provisionerless.box -- name: fedora-19 - driver_config: - box: opscode_fedora-19_chef-provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_fedora-19_chef-provisionerless.box -- name: fedora-20 - driver_config: - box: opscode_fedora-20_chef-provisionerless - box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_fedora-20_chef-provisionerless.box + - name: ubuntu-12.04 + - name: ubuntu-14.04 + - name: ubuntu-16.04 + - name: debian-7.11 + - name: debian-8.5 + - name: centos-6.8 + - name: centos-7.2 + - name: freebsd-9.3 + - name: freebsd-10.3 + - name: fedora-21 + - name: fedora-22 + - name: fedora-23 + - name: fedora-24 suites: -- name: default - run_list: - - recipe[hostname::default] - attributes: - set_fqdn: test.example.com -- name: wildcard - run_list: - - recipe[hostname::default] - provisioner: - solo_rb: - node_name: test - attributes: - set_fqdn: '*.example.com' + - name: default + run_list: + - recipe[hostname::default] + attributes: + set_fqdn: test.example.com + - name: wildcard + run_list: + - recipe[hostname::default] + provisioner: + solo_rb: + node_name: test + attributes: + set_fqdn: '*.example.com' diff --git a/cookbooks/hostname/.rspec b/cookbooks/hostname/.rspec new file mode 100644 index 0000000..4e1e0d2 --- /dev/null +++ b/cookbooks/hostname/.rspec @@ -0,0 +1 @@ +--color diff --git a/cookbooks/hostname/.rubocop.yml b/cookbooks/hostname/.rubocop.yml index 1391b04..68797c4 100644 --- a/cookbooks/hostname/.rubocop.yml +++ b/cookbooks/hostname/.rubocop.yml @@ -1,12 +1,23 @@ AllCops: + DisplayCopNames: true Exclude: - tmp/** -Documentation: +Lint/AmbiguousBlockAssociation: Enabled: false -LineLength: +Metrics/BlockLength: Enabled: false -SingleSpaceBeforeFirstArg: +Metrics/LineLength: + Enabled: false + +Style/Documentation: + Exclude: + - Thorfile + +Style/PercentLiteralDelimiters: + Enabled: false + +Style/SingleSpaceBeforeFirstArg: Enabled: false diff --git a/cookbooks/hostname/.travis.yml b/cookbooks/hostname/.travis.yml index c8a111e..b2ed931 100644 --- a/cookbooks/hostname/.travis.yml +++ b/cookbooks/hostname/.travis.yml @@ -1,9 +1,10 @@ bundler_args: --without integration before_script: bundle exec berks install -script: bundle exec strainer test +script: bundle exec rake language: ruby rvm: - - 1.9.3 + - 2.3.1 +sudo: false notifications: hipchat: secure: ! 'mTePogP3SZVXbZ8l3o1yN+uszEEwQY3WgBXXXQc4hV1nLGhAXgjgj5ueCKAE diff --git a/cookbooks/hostname/Berksfile b/cookbooks/hostname/Berksfile index 454fbaf..0bda926 100644 --- a/cookbooks/hostname/Berksfile +++ b/cookbooks/hostname/Berksfile @@ -1,8 +1,8 @@ # -*- ruby -*- -source "https://supermarket.getchef.com" +source 'https://supermarket.getchef.com' metadata group :integration do - cookbook "minitest-handler" + cookbook 'minitest-handler' end diff --git a/cookbooks/hostname/CHANGELOG.md b/cookbooks/hostname/CHANGELOG.md index 7985bfc..fd93678 100644 --- a/cookbooks/hostname/CHANGELOG.md +++ b/cookbooks/hostname/CHANGELOG.md @@ -1,5 +1,18 @@ # Change History +0.4.2 (2017-05-04) +================== + - #51: Make host file idempotent on RHEL + - #52: Add `append_hostsfile_ip` logic for improved idempotence + - #55: Ensure sysctl `kernel.hostname` set correctly on RHEL + +0.4.1 (2017-04-24) +================== + - #43: Set unique hosts file entry for hostname + - #44: Make hostname mapping to `127.0.0.1` optional + - #59: Updates to resolve deprecations warnings + - #60, #61: various test fixes + 0.4.0 (2015-03-16) ================== - #40: Use file resources with lazy eval and notifies to prevent network restarts from occurring on every chef run (Matt Kasa) diff --git a/cookbooks/hostname/Gemfile b/cookbooks/hostname/Gemfile index 92369be..5a955a6 100644 --- a/cookbooks/hostname/Gemfile +++ b/cookbooks/hostname/Gemfile @@ -1,14 +1,13 @@ source 'https://rubygems.org' gem 'berkshelf' -gem 'chef', '~> 11.10' +gem 'chef', '~> 12.13' gem 'chefspec' -gem 'foodcritic', '~> 3.0' +gem 'foodcritic' gem 'rake' -gem 'strainer' gem 'rubocop' group :integration do - gem 'test-kitchen', '~> 1.0' gem 'kitchen-vagrant' + gem 'test-kitchen' end diff --git a/cookbooks/hostname/LICENSE b/cookbooks/hostname/LICENSE new file mode 100644 index 0000000..5fd6878 --- /dev/null +++ b/cookbooks/hostname/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011-2017 Maciej Pasternacki + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cookbooks/hostname/README.md b/cookbooks/hostname/README.md index f4b144b..988b256 100644 --- a/cookbooks/hostname/README.md +++ b/cookbooks/hostname/README.md @@ -1,5 +1,7 @@ # hostname cookbook +[![Build Status](https://travis-ci.org/3ofcoins/chef-cookbook-hostname.svg?branch=master)](https://travis-ci.org/3ofcoins/chef-cookbook-hostname) +[![Chef cookbook](https://img.shields.io/cookbook/v/hostname.svg)](https://supermarket.chef.io/cookbooks/hostname) ## Description Sets hostname and FQDN of the node. The latest code is hosted at @@ -30,7 +32,13 @@ and have node set its FQDN and hostname based on its chef node name - `node['hostname_cookbook']['hostsfile_ip']` -- IP used in `/etc/hosts` to correctly set FQDN (default: `127.0.1.1`) +- `node['hostname_cookbook']['hostsfile_aliases']` -- list of aliases used in + `/etc/hosts` for the ip set above (default: [`hostname`]) +- `node['hostname_cookbook']['hostsfile_include_hostname_in_aliases']` -- whether to include the hostname + at the end of the aliases list above (default: true) +- `node['hostname_cookbook']['append_hostsfile_ip']` -- Set to `false` to + prevent an entry for the node's hostname from being appended in `/etc/hosts` (default: `true`) ## Recipes diff --git a/cookbooks/hostname/Rakefile b/cookbooks/hostname/Rakefile new file mode 100644 index 0000000..638e011 --- /dev/null +++ b/cookbooks/hostname/Rakefile @@ -0,0 +1,15 @@ +require 'foodcritic' +require 'rspec/core/rake_task' +require 'rubocop/rake_task' + +RuboCop::RakeTask.new(:rubocop) + +FoodCritic::Rake::LintTask.new do |t| + t.options = { + fail_tags: ['any'] + } +end + +RSpec::Core::RakeTask.new(:spec) + +task default: %w[foodcritic rubocop spec] diff --git a/cookbooks/hostname/Strainerfile b/cookbooks/hostname/Strainerfile deleted file mode 100644 index f0aafd1..0000000 --- a/cookbooks/hostname/Strainerfile +++ /dev/null @@ -1,4 +0,0 @@ -rubocop: rubocop $COOKBOOK -knife test: knife cookbook test $COOKBOOK -foodcritic: foodcritic -c 11.6.0 --tags ~FC015 --epic-fail any $SANDBOX/$COOKBOOK -chefspec: rspec $SANDBOX/$COOKBOOK diff --git a/cookbooks/hostname/TESTING.md b/cookbooks/hostname/TESTING.md index a47af94..76fdc00 100644 --- a/cookbooks/hostname/TESTING.md +++ b/cookbooks/hostname/TESTING.md @@ -13,13 +13,12 @@ And then, to install all cookbooks: Local ----- - $ bundle exec strainer test + $ bundle exec rake The above runs: - - rubocop - - `knife cookbook test` tests - - Food Critic lint + - rubocop lint + - Foodcritic lint - Chefspec tests Chefspec tests (the interesting part) are in `spec/`. diff --git a/cookbooks/hostname/Thorfile b/cookbooks/hostname/Thorfile index c6f8757..97baa90 100644 --- a/cookbooks/hostname/Thorfile +++ b/cookbooks/hostname/Thorfile @@ -6,12 +6,12 @@ require 'bundler/setup' require 'shellwords' class Cookbook < Thor - COOKBOOK_NAME = 'hostname' - COOKBOOK_CATEGORY = 'utilities' + COOKBOOK_NAME = 'hostname'.freeze + COOKBOOK_CATEGORY = 'utilities'.freeze include Thor::Actions - desc :edit, "Edit cookbook in browser" + desc :edit, 'Edit cookbook in browser' def edit open "http://community.opscode.com/cookbooks/#{COOKBOOK_NAME}/edit" end @@ -35,7 +35,7 @@ class Cookbook < Thor def open_cmd @open_cmd ||= %w[open xdg-open].find do |command| system "which #{command} >/dev/null 2>&1" - $?.success? + $CHILD_STATUS.success? end end end diff --git a/cookbooks/hostname/attributes/default.rb b/cookbooks/hostname/attributes/default.rb index f84d8d6..0aac597 100644 --- a/cookbooks/hostname/attributes/default.rb +++ b/cookbooks/hostname/attributes/default.rb @@ -1,4 +1,7 @@ # -*- coding: utf-8 -*- default['hostname_cookbook']['hostsfile_ip'] = '127.0.1.1' -default['hostname_cookbook']['hostsfile_ip_interface'] = 'lo0' if platform == 'freebsd' +default['hostname_cookbook']['hostsfile_ip_interface'] = 'lo0' if node['platform'] == 'freebsd' +default['hostname_cookbook']['hostsfile_aliases'] = [] +default['hostname_cookbook']['hostsfile_include_hostname_in_aliases'] = true +default['hostname_cookbook']['append_hostsfile_ip'] = true diff --git a/cookbooks/hostname/metadata.rb b/cookbooks/hostname/metadata.rb index cef053a..8355ea1 100644 --- a/cookbooks/hostname/metadata.rb +++ b/cookbooks/hostname/metadata.rb @@ -6,10 +6,15 @@ maintainer_email 'maciej@3ofcoins.net' license 'MIT' description 'Configures hostname and FQDN' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '0.4.0' +version '0.4.2' supports 'debian' supports 'ubuntu' supports 'freebsd' depends 'hostsfile' + +source_url 'https://github.com/3ofcoins/chef-cookbook-hostname' if respond_to?(:source_url) +issues_url 'https://github.com/3ofcoins/chef-cookbook-hostname/issues' if respond_to?(:issues_url) + +chef_version '>= 12.1' if respond_to?(:chef_version) diff --git a/cookbooks/hostname/recipes/default.rb b/cookbooks/hostname/recipes/default.rb index ef05790..b9c1cf1 100644 --- a/cookbooks/hostname/recipes/default.rb +++ b/cookbooks/hostname/recipes/default.rb @@ -31,7 +31,10 @@ if fqdn fqdn =~ /^([^.]+)/ hostname = Regexp.last_match[1] - case node['platform'] + aliases = node['hostname_cookbook']['hostsfile_aliases'] + aliases += [hostname] if node['hostname_cookbook']['hostsfile_include_hostname_in_aliases'] + + case node['platform_family'] when 'freebsd' directory '/etc/rc.conf.d' do mode '0755' @@ -56,7 +59,7 @@ if fqdn notifies :reload, 'ohai[reload_hostname]', :immediately end - when 'centos', 'redhat', 'amazon', 'scientific' + when 'rhel' service 'network' do action :nothing end @@ -66,6 +69,7 @@ if fqdn content lazy { ::IO.read(hostfile).gsub(/^HOSTNAME=.*$/, "HOSTNAME=#{fqdn}") } + not_if { ::IO.read(hostfile) =~ /^HOSTNAME=#{fqdn}$/ } notifies :reload, 'ohai[reload_hostname]', :immediately notifies :restart, 'service[network]', :delayed end @@ -73,10 +77,13 @@ if fqdn sysctl = '/etc/sysctl.conf' file sysctl do action :create + regex = /^kernel\.hostname=.*/ + newline = "kernel.hostname=#{hostname}" content lazy { - ::IO.read(sysctl) + "kernel.hostname=#{hostname}\n" + original = ::IO.read(sysctl) + original.match(regex) ? original.gsub(regex, newline) : original + newline } - not_if { ::IO.read(sysctl) =~ /^kernel\.hostname=#{hostname}$/ } + not_if { ::IO.read(sysctl).scan(regex).last == newline } notifies :reload, 'ohai[reload_hostname]', :immediately notifies :restart, 'service[network]', :delayed end @@ -84,6 +91,14 @@ if fqdn only_if { node['hostname'] != hostname } notifies :reload, 'ohai[reload_hostname]', :immediately end + # update /etc/hostname in RHEL7+ + file '/etc/hostname' do + content "#{hostname}\n" + mode '0644' + only_if { ::File.exist?('/etc/hostname') } + notifies :reload, 'ohai[reload_hostname]', :immediately + end + else file '/etc/hostname' do content "#{hostname}\n" @@ -106,9 +121,11 @@ if fqdn hostsfile_entry 'set hostname' do ip_address node['hostname_cookbook']['hostsfile_ip'] hostname fqdn - aliases [hostname] + aliases aliases + unique true action :create notifies :reload, 'ohai[reload_hostname]', :immediately + only_if { node['hostname_cookbook']['append_hostsfile_ip'] } end ohai 'reload_hostname' do diff --git a/cookbooks/logrotate/.gitignore b/cookbooks/logrotate/.gitignore index f14bce1..abdff6a 100644 --- a/cookbooks/logrotate/.gitignore +++ b/cookbooks/logrotate/.gitignore @@ -1,3 +1,15 @@ +*.rbc +.config +coverage +InstalledFiles +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +_Store *~ *# .#* @@ -7,19 +19,33 @@ *.tmp *.bk *.bkup -.kitchen.local.yml -Berksfile.lock -.bundle/ -.cache/ -.kitchen/ -.vagrant/ -.vagrant.d/ -bin/ -tmp/ -vendor/ - -# RVM +# ruby/bundler files .ruby-version .ruby-gemset -.rvmrc \ No newline at end of file +.rvmrc +Gemfile.lock +.bundle +*.gem + +# YARD artifacts +.yardoc +_yardoc +doc/ +.idea + +# chef stuff +Berksfile.lock +.kitchen +.kitchen.local.yml +vendor/ +.coverage/ +.zero-knife.rb +Policyfile.lock.json +Cheffile.lock +.librarian/ + +# vagrant stuff +.vagrant/ +.vagrant.d/ +.kitchen/ diff --git a/cookbooks/logrotate/.kitchen.yml b/cookbooks/logrotate/.kitchen.yml index cd43292..8952c71 100644 --- a/cookbooks/logrotate/.kitchen.yml +++ b/cookbooks/logrotate/.kitchen.yml @@ -1,12 +1,21 @@ -driver_plugin: vagrant -driver_config: - require_chef_omnibus: true +driver: + name: vagrant + +provisioner: + name: chef_zero + # We have tests that ensure our deprecated features still + # work so we can't turn this on globally. + # deprecations_as_errors: true platforms: - - name: ubuntu-12.04 - run_list: - - recipe[fake::prep] - - name: centos-6.7 + - name: centos-6.8 + - name: centos-7.3 + # - name: debian-7.11 + - name: debian-8.6 + - name: fedora-25 + - name: opensuse-leap-42.1 + - name: ubuntu-14.04 + - name: ubuntu-16.04 suites: - name: default diff --git a/cookbooks/logrotate/.rubocop.yml b/cookbooks/logrotate/.rubocop.yml deleted file mode 100644 index 3e61476..0000000 --- a/cookbooks/logrotate/.rubocop.yml +++ /dev/null @@ -1,4 +0,0 @@ -AllCops: - Exclude: - - vendor/** - - .kitchen/** \ No newline at end of file diff --git a/cookbooks/logrotate/.travis.yml b/cookbooks/logrotate/.travis.yml index 2d48aff..2adff2a 100644 --- a/cookbooks/logrotate/.travis.yml +++ b/cookbooks/logrotate/.travis.yml @@ -1,10 +1,20 @@ +# Use Travis's cointainer based infrastructure sudo: false +addons: + apt: + sources: + - chef-stable-precise + packages: + - chefdk + branches: only: - master -language: ruby -cache: bundler -rvm: - - 2.2 + +# Ensure we make ChefDK's Ruby the default +install: echo "Using ChefDK for all dependencies" +before_script: + - eval "$(/opt/chefdk/bin/chef shell-init bash)" + script: - make travis diff --git a/cookbooks/logrotate/Berksfile b/cookbooks/logrotate/Berksfile index 1e01c28..4a0c13f 100644 --- a/cookbooks/logrotate/Berksfile +++ b/cookbooks/logrotate/Berksfile @@ -1,7 +1,7 @@ -source "https://supermarket.getchef.com" +source 'https://supermarket.chef.io' metadata group :development do - cookbook "fake", path: "test/fixtures/cookbooks/fake" + cookbook 'fake', path: 'test/fixtures/cookbooks/fake' end diff --git a/cookbooks/logrotate/CHANGELOG.md b/cookbooks/logrotate/CHANGELOG.md index 034fc1e..cbe0c6f 100644 --- a/cookbooks/logrotate/CHANGELOG.md +++ b/cookbooks/logrotate/CHANGELOG.md @@ -3,6 +3,34 @@ logrotate Cookbook CHANGELOG This file is used to list changes made in each version of the logrotate cookbook. +v2.2.0 +------ +# Compatibility Notes + +The `compat_resource` dependency was removed. This means we now +require Chef 12.5 or higher. It also means we now better support Chef +13. + +# Enhancements + +- The global configuration now supports scripts. +- The package install action (upgrade by default) is now configurable + via an attribute. +- The development environment now more closely follows modern cookbook + practices. + +# Bug Fixes + +- ChefSpec matcher now correctly calls ChefSpec.define_matcher. +- +# Contributors + +- Austin Heiman +- Baptiste Courtois +- Bogdan Katynski +- Thomas Dziedzic +- Tim Smith + v2.1.0 ------ diff --git a/cookbooks/logrotate/CONTRIBUTING.md b/cookbooks/logrotate/CONTRIBUTING.md index 11f715d..f69f59f 100644 --- a/cookbooks/logrotate/CONTRIBUTING.md +++ b/cookbooks/logrotate/CONTRIBUTING.md @@ -16,7 +16,7 @@ ### Requirements - Ruby 2.0+ -- Bundler (`gem install bundler`) +- Latest ChefDK - [Vagrant](https://vagrantup.com) - [VirtualBox](https://virtualbox.org) @@ -24,15 +24,15 @@ 1. Clone the git repository from GitHub: - $ git clone git@github.com:stevendanna/logrotate.git + git clone git@github.com:stevendanna/logrotate.git -2. Install the dependencies using bundler: +2. Ensure you have ChefDK installed: - $ bundle install + chef --version 3. Create a branch for your changes: - $ git checkout -b my_bug_fix + git checkout -b my_bug_fix 4. Make any changes diff --git a/cookbooks/logrotate/Gemfile b/cookbooks/logrotate/Gemfile deleted file mode 100644 index c7a8252..0000000 --- a/cookbooks/logrotate/Gemfile +++ /dev/null @@ -1,11 +0,0 @@ -source "https://rubygems.org" - -gem "berkshelf", "~> 4.0" -gem "chefspec", "~> 4.0" -gem "foodcritic", "~> 6.0" -gem "chefstyle", github: "chef/chefstyle" - -group :integration do - gem "test-kitchen", "~> 1.0" - gem "kitchen-vagrant", "~> 0.11" -end diff --git a/cookbooks/logrotate/Gemfile.lock b/cookbooks/logrotate/Gemfile.lock deleted file mode 100644 index 8d4c49c..0000000 --- a/cookbooks/logrotate/Gemfile.lock +++ /dev/null @@ -1,275 +0,0 @@ -GIT - remote: git://github.com/chef/chefstyle.git - revision: cc37808b7849fdcf49f04011626143940f83fe92 - specs: - chefstyle (0.3.1) - rubocop (= 0.39.0) - -GEM - remote: https://rubygems.org/ - specs: - addressable (2.4.0) - artifactory (2.3.2) - ast (2.2.0) - berkshelf (4.3.2) - addressable (~> 2.3, >= 2.3.4) - berkshelf-api-client (~> 2.0, >= 2.0.2) - buff-config (~> 1.0) - buff-extensions (~> 1.0) - buff-shell_out (~> 0.1) - celluloid (= 0.16.0) - celluloid-io (~> 0.16.1) - cleanroom (~> 1.0) - faraday (~> 0.9) - httpclient (~> 2.7) - minitar (~> 0.5, >= 0.5.4) - octokit (~> 4.0) - retryable (~> 2.0) - ridley (~> 4.5) - solve (~> 2.0) - thor (~> 0.19) - berkshelf-api-client (2.0.2) - faraday (~> 0.9.1) - httpclient (~> 2.7.0) - ridley (~> 4.5) - buff-config (1.0.1) - buff-extensions (~> 1.0) - varia_model (~> 0.4) - buff-extensions (1.0.0) - buff-ignore (1.1.1) - buff-ruby_engine (0.1.0) - buff-shell_out (0.2.0) - buff-ruby_engine (~> 0.1.0) - builder (3.2.2) - celluloid (0.16.0) - timers (~> 4.0.0) - celluloid-io (0.16.2) - celluloid (>= 0.16.0) - nio4r (>= 1.1.0) - chef (12.9.38) - bundler (>= 1.10) - chef-config (= 12.9.38) - chef-zero (~> 4.5) - diff-lcs (~> 1.2, >= 1.2.4) - erubis (~> 2.7) - ffi-yajl (~> 2.2) - highline (~> 1.6, >= 1.6.9) - mixlib-authentication (~> 1.4) - mixlib-cli (~> 1.4) - mixlib-log (~> 1.3) - mixlib-shellout (~> 2.0) - net-sftp (~> 2.1, >= 2.1.2) - net-ssh (>= 2.9, < 4.0) - net-ssh-multi (~> 1.1) - ohai (>= 8.6.0.alpha.1, < 9) - plist (~> 3.2) - proxifier (~> 1.0) - rspec-core (~> 3.4) - rspec-expectations (~> 3.4) - rspec-mocks (~> 3.4) - rspec_junit_formatter (~> 0.2.0) - serverspec (~> 2.7) - specinfra (~> 2.10) - syslog-logger (~> 1.6) - uuidtools (~> 2.1.5) - chef-config (12.9.38) - fuzzyurl (~> 0.8.0) - mixlib-config (~> 2.0) - mixlib-shellout (~> 2.0) - chef-zero (4.6.1) - ffi-yajl (~> 2.2) - hashie (>= 2.0, < 4.0) - mixlib-log (~> 1.3) - rack - uuidtools (~> 2.1) - chefspec (4.6.1) - chef (>= 11.14) - fauxhai (~> 3.2) - rspec (~> 3.0) - cleanroom (1.0.0) - cucumber-core (1.4.0) - gherkin (~> 3.2.0) - diff-lcs (1.2.5) - erubis (2.7.0) - faraday (0.9.2) - multipart-post (>= 1.2, < 3) - fauxhai (3.3.0) - net-ssh - ffi (1.9.10) - ffi-yajl (2.2.3) - libyajl2 (~> 1.2) - foodcritic (6.1.1) - cucumber-core (>= 1.3) - erubis - nokogiri (>= 1.5, < 2.0) - rake - rufus-lru (~> 1.0) - treetop (~> 1.4) - yajl-ruby (~> 1.1) - fuzzyurl (0.8.0) - gherkin (3.2.0) - hashie (3.4.3) - highline (1.7.8) - hitimes (1.2.3) - httpclient (2.7.1) - ipaddress (0.8.3) - json (1.8.3) - kitchen-vagrant (0.20.0) - test-kitchen (~> 1.4) - libyajl2 (1.2.0) - mini_portile2 (2.0.0) - minitar (0.5.4) - mixlib-authentication (1.4.0) - mixlib-log - rspec-core (~> 3.2) - rspec-expectations (~> 3.2) - rspec-mocks (~> 3.2) - mixlib-cli (1.5.0) - mixlib-config (2.2.1) - mixlib-install (1.0.7) - artifactory - mixlib-shellout - mixlib-versioning - mixlib-log (1.6.0) - mixlib-shellout (2.2.6) - mixlib-versioning (1.1.0) - molinillo (0.4.4) - multi_json (1.11.2) - multipart-post (2.0.0) - net-scp (1.2.1) - net-ssh (>= 2.6.5) - net-sftp (2.1.2) - net-ssh (>= 2.6.5) - net-ssh (3.1.1) - net-ssh-gateway (1.2.0) - net-ssh (>= 2.6.5) - net-ssh-multi (1.2.1) - net-ssh (>= 2.6.5) - net-ssh-gateway (>= 1.2.0) - net-telnet (0.1.1) - nio4r (1.2.1) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) - octokit (4.3.0) - sawyer (~> 0.7.0, >= 0.5.3) - ohai (8.14.0) - chef-config (>= 12.5.0.alpha.1, < 13) - ffi (~> 1.9) - ffi-yajl (~> 2.2) - ipaddress - mixlib-cli - mixlib-config (~> 2.0) - mixlib-log - mixlib-shellout (~> 2.0) - plist (~> 3.1) - systemu (~> 2.6.4) - wmi-lite (~> 1.0) - parser (2.3.0.7) - ast (~> 2.2) - plist (3.2.0) - polyglot (0.3.5) - powerpack (0.1.1) - proxifier (1.0.3) - rack (1.6.4) - rainbow (2.1.0) - rake (11.1.2) - retryable (2.0.3) - ridley (4.5.0) - addressable - buff-config (~> 1.0) - buff-extensions (~> 1.0) - buff-ignore (~> 1.1) - buff-shell_out (~> 0.1) - celluloid (~> 0.16.0) - celluloid-io (~> 0.16.1) - chef-config (>= 12.5.0) - erubis - faraday (~> 0.9.0) - hashie (>= 2.0.2, < 4.0.0) - httpclient (~> 2.7) - json (>= 1.7.7) - mixlib-authentication (>= 1.3.0) - retryable (~> 2.0) - semverse (~> 1.1) - varia_model (~> 0.4.0) - rspec (3.4.0) - rspec-core (~> 3.4.0) - rspec-expectations (~> 3.4.0) - rspec-mocks (~> 3.4.0) - rspec-core (3.4.4) - rspec-support (~> 3.4.0) - rspec-expectations (3.4.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-its (1.2.0) - rspec-core (>= 3.0.0) - rspec-expectations (>= 3.0.0) - rspec-mocks (3.4.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.4.0) - rspec-support (3.4.1) - rspec_junit_formatter (0.2.3) - builder (< 4) - rspec-core (>= 2, < 4, != 2.12.0) - rubocop (0.39.0) - parser (>= 2.3.0.7, < 3.0) - powerpack (~> 0.1) - rainbow (>= 1.99.1, < 3.0) - ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.0, >= 1.0.1) - ruby-progressbar (1.7.5) - rufus-lru (1.0.5) - safe_yaml (1.0.4) - sawyer (0.7.0) - addressable (>= 2.3.5, < 2.5) - faraday (~> 0.8, < 0.10) - semverse (1.2.1) - serverspec (2.31.1) - multi_json - rspec (~> 3.0) - rspec-its - specinfra (~> 2.53) - sfl (2.2) - solve (2.0.3) - molinillo (~> 0.4.2) - semverse (~> 1.1) - specinfra (2.56.1) - net-scp - net-ssh (>= 2.7, < 4.0) - net-telnet - sfl - syslog-logger (1.6.8) - systemu (2.6.5) - test-kitchen (1.7.3) - mixlib-install (~> 1.0, >= 1.0.4) - mixlib-shellout (>= 1.2, < 3.0) - net-scp (~> 1.1) - net-ssh (>= 2.9, < 4.0) - safe_yaml (~> 1.0) - thor (~> 0.18) - thor (0.19.1) - timers (4.0.4) - hitimes - treetop (1.6.5) - polyglot (~> 0.3) - unicode-display_width (1.0.3) - uuidtools (2.1.5) - varia_model (0.4.1) - buff-extensions (~> 1.0) - hashie (>= 2.0.2, < 4.0.0) - wmi-lite (1.0.0) - yajl-ruby (1.2.1) - -PLATFORMS - ruby - -DEPENDENCIES - berkshelf (~> 4.0) - chefspec (~> 4.0) - chefstyle! - foodcritic (~> 6.0) - kitchen-vagrant (~> 0.11) - test-kitchen (~> 1.0) - -BUNDLED WITH - 1.11.2 diff --git a/cookbooks/logrotate/Makefile b/cookbooks/logrotate/Makefile index 315bc70..0feec86 100644 --- a/cookbooks/logrotate/Makefile +++ b/cookbooks/logrotate/Makefile @@ -1,13 +1,11 @@ -travis: bundle berks - bundle exec chefstyle -D - bundle exec foodcritic . - bundle exec rspec --color --format doc +all: delivery -integration: bundle berks - bundle exec kitchen test +travis: debug_version_info all -bundle: - bundle install +debug_version_info: + /opt/chefdk/embedded/bin/chef --version + /opt/chefdk/embedded/bin/cookstyle --version + /opt/chefdk/embedded/bin/foodcritic --version -berks: - bundle exec berks install +delivery: + /opt/chefdk/bin/chef exec delivery local all diff --git a/cookbooks/logrotate/README.md b/cookbooks/logrotate/README.md index 09123e9..a0ab6ff 100644 --- a/cookbooks/logrotate/README.md +++ b/cookbooks/logrotate/README.md @@ -6,11 +6,22 @@ application specific logrotate configuration. ## Requirements + +### Platforms + Should work on any platform that includes a 'logrotate' package and writes logrotate configuration to /etc/logrotate.d. Tested on Ubuntu and Centos. +### Chef + +- Chef 12.5+ + +### Cookbooks + +- none + ## Recipes ### global @@ -118,7 +129,7 @@ The resource takes the following properties: "logrotate.erb". - `template_mode`: the mode to create the logrotate template with - (default: "0440") + (default: "0644") - `template_owner`: the owner of the logrotate template (default: "root") diff --git a/cookbooks/logrotate/attributes/default.rb b/cookbooks/logrotate/attributes/default.rb index 4354527..0be2049 100644 --- a/cookbooks/logrotate/attributes/default.rb +++ b/cookbooks/logrotate/attributes/default.rb @@ -1,10 +1,10 @@ # -# Cookbook Name:: logrotate +# Cookbook:: logrotate # Attribute:: default # -# Copyright 2013, Chef Software, Inc -# Copyright 2015-2016, Steven Danna -# Copyright 2016, Bloomberg Finance L.P. +# Copyright:: 2013-2017, Chef Software, Inc +# Copyright:: 2015-2017, Steven Danna +# Copyright:: 2016-2017, Bloomberg Finance L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,36 +19,37 @@ # limitations under the License. # -default["logrotate"]["package"] = { - "name" => "logrotate", - "source" => nil, - "version" => nil, - "provider" => nil, +default['logrotate']['package'] = { + 'name' => 'logrotate', + 'source' => nil, + 'version' => nil, + 'provider' => nil, + 'action' => :upgrade, } -default["logrotate"]["directory"] = "/etc/logrotate.d" -default["logrotate"]["cron"]["install"] = platform?("solaris2") || platform?("aix") -default["logrotate"]["cron"]["name"] = "logrotate" -default["logrotate"]["cron"]["command"] = "/usr/sbin/logrotate /etc/logrotate.conf" -default["logrotate"]["cron"]["minute"] = 35 -default["logrotate"]["cron"]["hour"] = 2 +default['logrotate']['directory'] = '/etc/logrotate.d' +default['logrotate']['cron']['install'] = platform?('solaris2') || platform?('aix') +default['logrotate']['cron']['name'] = 'logrotate' +default['logrotate']['cron']['command'] = '/usr/sbin/logrotate /etc/logrotate.conf' +default['logrotate']['cron']['minute'] = 35 +default['logrotate']['cron']['hour'] = 2 -default["logrotate"]["global"] = { - "weekly" => true, - "rotate" => 4, - "create" => "", +default['logrotate']['global'] = { + 'weekly' => true, + 'rotate' => 4, + 'create' => '', - "/var/log/wtmp" => { - "missingok" => true, - "monthly" => true, - "create" => "0664 root utmp", - "rotate" => 1, + '/var/log/wtmp' => { + 'missingok' => true, + 'monthly' => true, + 'create' => '0664 root utmp', + 'rotate' => 1, }, - "/var/log/btmp" => { - "missingok" => true, - "monthly" => true, - "create" => "0660 root utmp", - "rotate" => 1, + '/var/log/btmp' => { + 'missingok' => true, + 'monthly' => true, + 'create' => '0660 root utmp', + 'rotate' => 1, }, } diff --git a/cookbooks/php-fpm/chefignore b/cookbooks/logrotate/chefignore similarity index 85% rename from cookbooks/php-fpm/chefignore rename to cookbooks/logrotate/chefignore index c37aacd..a976917 100644 --- a/cookbooks/php-fpm/chefignore +++ b/cookbooks/logrotate/chefignore @@ -1,5 +1,5 @@ # Put files/directories that should be ignored in this file when uploading -# or sharing to the community site. +# to a chef-server or supermarket. # Lines that start with '# ' are comments. # OS generated files # @@ -51,8 +51,16 @@ spec/* spec/fixtures/* test/* features/* +examples/* Guardfile Procfile +.kitchen* +.rubocop.yml +spec/* +Rakefile +.travis.yml +.foodcritic +.codeclimate.yml # SCM # ####### @@ -76,8 +84,10 @@ tmp # Cookbooks # ############# -CONTRIBUTING +CONTRIBUTING* CHANGELOG* +TESTING* +MAINTAINERS.toml # Strainer # ############ @@ -90,12 +100,3 @@ Strainerfile ########### .vagrant Vagrantfile - -# Travis # -########## -.travis.yml - -# Other # -########## -.sandbox -.bundle diff --git a/cookbooks/logrotate/libraries/logrotate_config.rb b/cookbooks/logrotate/libraries/logrotate_config.rb index 5ad750d..5f20d3d 100644 --- a/cookbooks/logrotate/libraries/logrotate_config.rb +++ b/cookbooks/logrotate/libraries/logrotate_config.rb @@ -1,8 +1,8 @@ # -# Cookbook Name:: logrotate +# Cookbook:: logrotate # Library:: CookbookLogrotate # -# Copyright 2013, Chef +# Copyright:: 2013-2017, Chef # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,24 +19,24 @@ # Helper module for Logrotate configuration module CookbookLogrotate module CookbookLogrotate - DIRECTIVES = %w{compress copy copytruncate daily dateext - dateyesterday delaycompress hourly ifempty mailfirst maillast - missingok monthly nocompress nocopy nocopytruncate nocreate nocreateolddir - nodelaycompress nodateext nomail nomissingok noolddir - nosharedscripts noshred notifempty renamecopy sharedscripts shred weekly - yearly} unless const_defined?(:DIRECTIVES) + DIRECTIVES = %w(compress copy copytruncate daily dateext + dateyesterday delaycompress hourly ifempty mailfirst maillast + missingok monthly nocompress nocopy nocopytruncate nocreate nocreateolddir + nodelaycompress nodateext nomail nomissingok noolddir + nosharedscripts noshred notifempty renamecopy sharedscripts shred weekly + yearly).freeze unless const_defined?(:DIRECTIVES) - VALUES = %w{compresscmd uncompresscmd compressext compressoptions - create createolddir dateformat include mail extension maxage minsize maxsize - rotate size shredcycles start tabooext su olddir} unless const_defined?(:VALUES) + VALUES = %w(compresscmd uncompresscmd compressext compressoptions + create createolddir dateformat include mail extension maxage minsize maxsize + rotate size shredcycles start tabooext su olddir).freeze unless const_defined?(:VALUES) - SCRIPTS = %w{firstaction prerotate postrotate lastaction preremove} unless const_defined?(:SCRIPTS) + SCRIPTS = %w(firstaction prerotate postrotate lastaction preremove).freeze unless const_defined?(:SCRIPTS) - DIRECTIVES_AND_VALUES = DIRECTIVES + VALUES unless const_defined?(:DIRECTIVES_AND_VALUES) + DIRECTIVES_AND_VALUES_AND_SCRIPTS = DIRECTIVES + VALUES + SCRIPTS unless const_defined?(:DIRECTIVES_AND_VALUES_AND_SCRIPTS) # Helper class for creating configurations class LogrotateConfiguration - attr_reader :directives, :values, :paths + attr_reader :directives, :values, :scripts, :paths class << self def from_hash(hash) @@ -52,27 +52,23 @@ module CookbookLogrotate end def paths_from(hash) - hash.select { |k| !(DIRECTIVES_AND_VALUES.include?(k)) }.reduce({}) do |accum_paths, (path, config)| + hash.select { |k| !DIRECTIVES_AND_VALUES_AND_SCRIPTS.include?(k) }.each_with_object({}) do |(path, config), accum_paths| accum_paths[path] = { - "directives" => directives_from(config), - "values" => values_from(config), - "scripts" => scripts_from(config), + 'directives' => directives_from(config), + 'values' => values_from(config), + 'scripts' => scripts_from(config), } - - accum_paths end end def scripts_from(hash) defined_scripts = hash.select { |k| SCRIPTS.include?(k) } - defined_scripts.reduce({}) do |accum_scripts, (script, lines)| - if lines.respond_to?(:join) - accum_scripts[script] = lines.join("\n") - else - accum_scripts[script] = lines - end - - accum_scripts + defined_scripts.each_with_object({}) do |(script, lines), accum_scripts| + accum_scripts[script] = if lines.respond_to?(:join) + lines.join("\n") + else + lines + end end end end @@ -82,6 +78,7 @@ module CookbookLogrotate def initialize(hash) @directives = LogrotateConfiguration.directives_from(hash) @values = LogrotateConfiguration.values_from(hash) + @scripts = LogrotateConfiguration.scripts_from(hash) @paths = LogrotateConfiguration.paths_from(hash) end end diff --git a/cookbooks/logrotate/libraries/matchers.rb b/cookbooks/logrotate/libraries/matchers.rb index 11171a2..82d5e18 100644 --- a/cookbooks/logrotate/libraries/matchers.rb +++ b/cookbooks/logrotate/libraries/matchers.rb @@ -1,4 +1,6 @@ if defined?(ChefSpec) + ChefSpec.define_matcher :logrotate_app + def enable_logrotate_app(resource) ChefSpec::Matchers::ResourceMatcher.new(:logrotate_app, :enable, resource) end diff --git a/cookbooks/logrotate/metadata.json b/cookbooks/logrotate/metadata.json index 6222e50..ebda691 100644 --- a/cookbooks/logrotate/metadata.json +++ b/cookbooks/logrotate/metadata.json @@ -16,7 +16,7 @@ "ubuntu": ">= 0.0.0" }, "dependencies": { - "compat_resource": ">= 0.0.0" + }, "recommendations": { @@ -42,12 +42,14 @@ "recipes": { "logrotate": "Installs logrotate package" }, - "version": "2.1.0", + "version": "2.2.0", "source_url": "https://github.com/stevendanna/logrotate", "issues_url": "https://github.com/stevendanna/logrotate/issues", "privacy": false, "chef_versions": [ - + [ + ">= 12.5" + ] ], "ohai_versions": [ diff --git a/cookbooks/logrotate/metadata.rb b/cookbooks/logrotate/metadata.rb index 9134e97..e0899fc 100644 --- a/cookbooks/logrotate/metadata.rb +++ b/cookbooks/logrotate/metadata.rb @@ -1,19 +1,18 @@ -name "logrotate" -maintainer "Steven Danna" -maintainer_email "steve@chef.io" -license "Apache 2.0" -description "Installs logrotate package and provides a definition for logrotate configs" -long_description "Installs the logrotate package, manages /etc/logrotate.conf, and provides a logrotate_app definition." -version "2.1.0" +name 'logrotate' +maintainer 'Steven Danna' +maintainer_email 'steve@chef.io' +license 'Apache 2.0' +description 'Installs logrotate package and provides a definition for logrotate configs' +long_description 'Installs the logrotate package, manages /etc/logrotate.conf, and provides a logrotate_app definition.' +version '2.2.0' -source_url "https://github.com/stevendanna/logrotate" if respond_to?(:source_url) -issues_url "https://github.com/stevendanna/logrotate/issues" if respond_to?(:issues_url) +recipe 'logrotate', 'Installs logrotate package' +provides 'logrotate_app' -recipe "logrotate", "Installs logrotate package" -provides "logrotate_app" - -depends "compat_resource" - -%w{amazon centos debian fedora redhat scientific solaris2 ubuntu}.each do |platform| +%w(amazon centos debian fedora redhat scientific solaris2 ubuntu).each do |platform| supports platform end + +source_url 'https://github.com/stevendanna/logrotate' +issues_url 'https://github.com/stevendanna/logrotate/issues' +chef_version '>= 12.5' if respond_to?(:chef_version) diff --git a/cookbooks/logrotate/recipes/default.rb b/cookbooks/logrotate/recipes/default.rb index 80fd168..482e616 100644 --- a/cookbooks/logrotate/recipes/default.rb +++ b/cookbooks/logrotate/recipes/default.rb @@ -1,10 +1,10 @@ # -# Cookbook Name:: logrotate +# Cookbook:: logrotate # Recipe:: default # -# Copyright 2009-2013, Chef Software, Inc. -# Copyright 2015-2016, Steven Danna -# Copyright 2016, Bloomberg Finance L.P. +# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2015-2017, Steven Danna +# Copyright:: 2016-2017, Bloomberg Finance L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,25 +18,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # -return if platform?("windows") +return if platform?('windows') -package node["logrotate"]["package"]["name"] do - provider node["logrotate"]["package"]["provider"] if node["logrotate"]["package"]["provider"] - source node["logrotate"]["package"]["source"] if node["logrotate"]["package"]["source"] - version node["logrotate"]["package"]["version"] if node["logrotate"]["package"]["version"] - action :upgrade +package node['logrotate']['package']['name'] do + provider node['logrotate']['package']['provider'] if node['logrotate']['package']['provider'] + source node['logrotate']['package']['source'] if node['logrotate']['package']['source'] + version node['logrotate']['package']['version'] if node['logrotate']['package']['version'] + action node['logrotate']['package']['action'] end -directory node["logrotate"]["directory"] do - owner "root" - group node["root_group"] - mode "0755" +directory node['logrotate']['directory'] do + owner 'root' + group node['root_group'] + mode '0755' end -if node["logrotate"]["cron"]["install"] # ~FC023 - cron node["logrotate"]["cron"]["name"] do - minute node["logrotate"]["cron"]["minute"] - hour node["logrotate"]["cron"]["hour"] - command node["logrotate"]["cron"]["command"] +if node['logrotate']['cron']['install'] # ~FC023 + cron node['logrotate']['cron']['name'] do + minute node['logrotate']['cron']['minute'] + hour node['logrotate']['cron']['hour'] + command node['logrotate']['cron']['command'] end end diff --git a/cookbooks/logrotate/recipes/global.rb b/cookbooks/logrotate/recipes/global.rb index 2808806..3dbf0a3 100644 --- a/cookbooks/logrotate/recipes/global.rb +++ b/cookbooks/logrotate/recipes/global.rb @@ -1,8 +1,8 @@ # -# Cookbook Name:: logrotate +# Cookbook:: logrotate # Recipe:: default # -# Copyright 2009-2013, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,14 +17,14 @@ # limitations under the License. # -include_recipe "logrotate::default" +include_recipe 'logrotate::default' -parsed_configuration = CookbookLogrotate::LogrotateConfiguration.from_hash(node["logrotate"]["global"].to_hash) +parsed_configuration = CookbookLogrotate::LogrotateConfiguration.from_hash(node['logrotate']['global'].to_hash) -template "/etc/logrotate.conf" do - source "logrotate-global.erb" - mode "0644" +template '/etc/logrotate.conf' do + source 'logrotate-global.erb' + mode '0644' variables( - :configuration => parsed_configuration + configuration: parsed_configuration ) end diff --git a/cookbooks/logrotate/resources/app.rb b/cookbooks/logrotate/resources/app.rb index 8c5fb2b..0958e69 100644 --- a/cookbooks/logrotate/resources/app.rb +++ b/cookbooks/logrotate/resources/app.rb @@ -1,5 +1,5 @@ # -# Copyright 2016, Steven Danna +# Copyright:: 2016-2017, Steven Danna # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,20 +17,20 @@ resource_name :logrotate_app property :path, [String, Array], required: true -property :frequency, String, default: "weekly" -property :cookbook, default: "logrotate" -property :template_name, default: "logrotate.erb" -property :template_mode, default: "0644" -property :template_owner, default: "root" -property :template_group, default: "root" -property :base_dir, String, default: "/etc/logrotate.d" +property :frequency, String, default: 'weekly' +property :cookbook, default: 'logrotate' +property :template_name, default: 'logrotate.erb' +property :template_mode, default: '0644' +property :template_owner, default: 'root' +property :template_group, default: 'root' +property :base_dir, String, default: '/etc/logrotate.d' -property :options, [Array, String], default: %w{missingok compress delaycompress copytruncate notifempty} +property :options, [Array, String], default: %w(missingok compress delaycompress copytruncate notifempty) default_action :enable CookbookLogrotate::SCRIPTS.each do |script_name| - property script_name.to_sym, coerce: Proc.new { |val| Array(val).join("\n") } + property script_name.to_sym, coerce: proc { |val| Array(val).join("\n") } end CookbookLogrotate::VALUES.each do |configurable_name| @@ -42,15 +42,15 @@ property :sharedscripts, [TrueClass, FalseClass], default: false property :enable, [TrueClass, FalseClass], default: true action :enable do - if !new_resource.enable - Chef::Log.deprecation "Use `action :disable` rather than `enable false` in the logrotate_app resource" + unless new_resource.enable + Chef::Log.deprecation 'Use `action :disable` rather than `enable false` in the logrotate_app resource' action_disable return true end logrotate_config = { # The path should be a space separated list of quoted filesystem paths - path: Array(new_resource.path).map { |path| path.to_s.inspect }.join(" "), + path: Array(new_resource.path).map { |path| path.to_s.inspect }.join(' '), frequency: new_resource.frequency, directives: handle_options(new_resource), scripts: handle_scripts(new_resource), @@ -58,9 +58,9 @@ action :enable do } directory new_resource.base_dir do - owner "root" - group node["root_group"] - mode "0755" + owner 'root' + group node['root_group'] + mode '0755' action :create end @@ -84,7 +84,7 @@ end def handle_configurables(new_resource) configurables = {} CookbookLogrotate::VALUES.each do |opt_name| - if value = new_resource.send(opt_name.to_sym) + if value = new_resource.send(opt_name.to_sym) # rubocop: disable Lint/AssignmentInCondition configurables[opt_name] = value end end @@ -94,7 +94,7 @@ end def handle_scripts(new_resource) scripts = {} CookbookLogrotate::SCRIPTS.each do |script_name| - if script_body = new_resource.send(script_name.to_sym) + if script_body = new_resource.send(script_name.to_sym) # rubocop: disable Lint/AssignmentInCondition scripts[script_name] = script_body end end @@ -109,8 +109,8 @@ def handle_options(new_resource) end if new_resource.sharedscripts - Chef::Log.deprecation("The sharedscripts resource property is deprecated. Use the options property instead to set this value") - opts << "sharedscripts" + Chef::Log.deprecation('The sharedscripts resource property is deprecated. Use the options property instead to set this value') + opts << 'sharedscripts' end opts end diff --git a/cookbooks/logrotate/templates/default/logrotate-global.erb b/cookbooks/logrotate/templates/default/logrotate-global.erb index 96ba504..f59eda0 100644 --- a/cookbooks/logrotate/templates/default/logrotate-global.erb +++ b/cookbooks/logrotate/templates/default/logrotate-global.erb @@ -9,6 +9,12 @@ <%= k %> <%= v %> <% end -%> +<% @configuration.scripts.each do | scripttype, body | -%> +<%= scripttype %> +<%= body %> +endscript +<% end -%> + include /etc/logrotate.d <% @configuration.paths.each do |path, path_config| -%> diff --git a/cookbooks/mysql/CHANGELOG.md b/cookbooks/mysql/CHANGELOG.md index 8fd0aa8..0e01d05 100644 --- a/cookbooks/mysql/CHANGELOG.md +++ b/cookbooks/mysql/CHANGELOG.md @@ -2,6 +2,94 @@ This file is used to list changes made in each version of the mysql cookbook. +## 8.4.0 (2017-05-30) + +- Fix client/server install on Amazon Linux and add testing +- Remove support for Ubuntu Precise since it's EOL +- Add Amazon Linux testing + +## 8.3.1 (2017-04-04) + +- Fix an ignoring of 'cookbook' attribute by 'mysql_config' resource +- Remove unused helper method +- Call out the supported platform versions in the metadata +- Switch to Delivery Local and rename the docked config +- Remove mention of the EOL opensuse 13.x in the readme + +## 8.3.0 (2017-03-20) +- Refactor mysql_service_manager_upstart.rb to eliminate use of cloned resource + +## 8.2.0 (2016-12-03) + +- Include client development packages on RHEL/SUSE platforms + +## 8.1.1 (2016-10-31) +- Fixing CVE-2016-6662 - Reverting execure bit on mysql config + +## 8.1.0 (2016-10-29) + +- Drop hardcoded, specific package version logic that broke many users + +## 8.0.4 (2016-09-26) +- Bump debian version +- Updated packages for 12.04 and 14.04 too +- Add chef_version metadata +- Update platforms in the kitchen file +- Add selinux to the Berksfile for testing +- Make sure yum repos are setup in local Test Kitchen + +## 8.0.3 (2016-09-14) +- [GH-390] Fix #390 incorrect escaping of initial_root_password +- Updated package versions for Ubuntu 16.04 +- Testing updates + +# v8.0.2 (2016-08-25) +- Various bug fixed and updates to package version strings + +# v8.0.1 (2016-07-20) +- Fixed a regression in the mysql_client resource where the action was changed from create to install in the 8.0 release +- Added oracle, opensuse, and opensuseleap as supported platforms in the metadata + +# v8.0.0 (2016-07-11) + +- Converting from LWRP to custom resources +- Removing yum-mysql and other dependencies. +- ^ BREAKING CHANGE: RHELish users are now responsible + for including a recipe from the "yum-mysql" or equivalent + cookbook before utilizing the mysql_* resources. +- More thoughtful ChefSpec +- Renaming "replication" test suite to "smoke" +- Moving to Inspec + +## v7.2.0 (2016-06-30) + +- Support openeSUSE leap +- Support Fedora 24 + +## v7.1.2 (2016-06-30) + +- Avoid deprecation warnings on the upcoming Chef 12.12 release + +## v7.1.1 (2016-06-03) + +- Fix apparmor blocking writes to non-default tmp_dirs +- Updated apparmor config to allow read & write to sock.lock file +- Use cookstyle instead of Rubocop directly + +## v7.1.0 (2016-05-11) + +- Added support for Ubuntu 16.04 + +## v7.0.0 (2016-04-19) + +- Removed support for legacy distros: Ubuntu 10.04/13.04/14.10/15.04, Fedora 20/21, OmniOS r151006, opensuse 11.3/12.0 +- Added support for Fedora 23, suse 13.X, and Ubuntu 16.04 +- Updated the systemd support to create unit files in /etc/systemd and not /usr/lib/systemd +- Adding umask to bash resource that sets root password PR #386 @gziskind +- Cleaned up the Test Kitchen config to test the right platform version + mysql pairings +- Added Travis CI Test Kitchen testing on Fedora 22/23 and removed Fedora 21 +- Updated the platforms used in the specs + ## v6.1.3 (2016-03-14) - Added support for Ubuntu 15.10 @@ -65,7 +153,7 @@ This file is used to list changes made in each version of the mysql cookbook. ## v6.0.21 (2015-04-08) -- Fix to Upstart prestart script when using custom socket +- Fix to Upstart prestart script when using custom socket - Adding --explicit_defaults_for_timestamp mysql_install_db_cmd for - 5.6 and above @@ -186,7 +274,7 @@ This file is used to list changes made in each version of the mysql cookbook. ## v5.5.4 (2014-10-07) -- Adding sensitive flag to execute resources to protect passwords from logs +- Adding sensitive flag to execute resources to protect passwords from logs ## v5.5.3 (2014-09-24) diff --git a/cookbooks/mysql/MAINTAINERS.md b/cookbooks/mysql/MAINTAINERS.md index c6a51ae..b3548a4 100644 --- a/cookbooks/mysql/MAINTAINERS.md +++ b/cookbooks/mysql/MAINTAINERS.md @@ -1,13 +1,10 @@ # Maintainers -This file lists how this cookbook project is maintained. When making changes to the system, this -file tells you who needs to review your patch - you need a simple majority of maintainers -for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need -to not receive a veto from a Lieutenant or the Project Lead. -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) -for details on the process and how to become a maintainer or the project lead. +This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. + +Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. # Project Maintainer * [Tim Smith](https://github.com/tas50) diff --git a/cookbooks/mysql/README.md b/cookbooks/mysql/README.md index 3baa1f6..dc046f0 100644 --- a/cookbooks/mysql/README.md +++ b/cookbooks/mysql/README.md @@ -2,16 +2,15 @@ [![Build Status](https://travis-ci.org/chef-cookbooks/mysql.svg?branch=master)](https://travis-ci.org/chef-cookbooks/mysql) [![Cookbook Version](https://img.shields.io/cookbook/v/mysql.svg)](https://supermarket.chef.io/cookbooks/mysql) -The Mysql Cookbook is a library cookbook that provides resource primitives (LWRPs) for use in recipes. It is designed to be a reference example for creating highly reusable cross-platform cookbooks. +The MySQL Cookbook is a library cookbook that provides resource primitives (LWRPs) for use in recipes. It is designed to be a reference example for creating highly reusable cross-platform cookbooks. ## Scope -This cookbook is concerned with the "MySQL Community Server", particularly those shipped with F/OSS Unix and Linux distributions. It does not address forks or value-added repackaged MySQL distributions like Drizzle, MariaDB, or Percona. +This cookbook is concerned with the "MySQL Community Server", particularly those shipped with F/OSS Unix and Linux distributions. It does not address forks or value-added repackaged MySQL distributions like MariaDB or Percona. ## Requirements -- Chef 11 or higher -- Ruby 1.9 or higher (preferably from the Chef full-stack installer) +- Chef 12.5 or higher - Network accessible package repositories - 'recipe[selinux::disabled]' on RHEL platforms @@ -20,42 +19,37 @@ This cookbook is concerned with the "MySQL Community Server", particularly those The following platforms have been tested with Test Kitchen: ``` -|----------------+-----+-----+-----+-----+-----| -| | 5.0 | 5.1 | 5.5 | 5.6 | 5.7 | -|----------------+-----+-----+-----+-----+-----| -| debian-7 | | | X | | | -|----------------+-----+-----+-----+-----+-----| -| ubuntu-12.04 | | | X | | | -|----------------+-----+-----+-----+-----+-----| -| ubuntu-14.04 | | | X | X | | -|----------------+-----+-----+-----+-----+-----| -| ubuntu-15.04 | | | | X | | -|----------------+-----+-----+-----+-----+-----| -| centos-5 | X | X | X | X | X | -|----------------+-----+-----+-----+-----+-----| -| centos-6 | | X | X | X | X | -|----------------+-----+-----+-----+-----+-----| -| centos-7 | | | X | X | X | -|----------------+-----+-----+-----+-----+-----| -| amazon | | | X | X | X | -|----------------+-----+-----+-----+-----+-----| -| fedora-22 | | | X | X | X | -|----------------+-----+-----+-----+-----+-----| -| fedora-23 | | | X | X | X | -|----------------+-----+-----+-----+-----+-----| +|----------------+-----+-----+-----+-----| +| | 5.1 | 5.5 | 5.6 | 5.7 | +|----------------+-----+-----+-----+-----| +| debian-7 | | X | | | +|----------------+-----+-----+-----+-----| +| debian-8 | | X | | | +|----------------+-----+-----+-----+-----| +| ubuntu-14.04 | | X | X | | +|----------------+-----+-----+-----+-----| +| ubuntu-16.04 | | | | X | +|----------------+-----+-----+-----+-----| +| centos-6 | X | X | X | X | +|----------------+-----+-----+-----+-----| +| centos-7 | | X | X | X | +|----------------+-----+-----+-----+-----| +| fedora | | | X | X | +|----------------+-----+-----+-----+-----| +| openSUSE Leap | | | X | | +|----------------+-----+-----+-----+-----| ``` ## Cookbook Dependencies -- yum-mysql-community -- smf +There are no hard coupled dependencies. However, there is a loose dependency on `yum-mysql-community` for RHEL/CentOS platforms. As of the 8.0 version of this cookbook, configuration of the package repos is now the responsibility of the user. ## Usage Place a dependency on the mysql cookbook in your cookbook's metadata.rb ```ruby -depends 'mysql', '~> 6.0' +depends 'mysql', '~> 8.0' ``` Then, in a recipe: @@ -180,7 +174,7 @@ Please note that when using `notifies` or `subscribes`, the resource to referenc - `:create` - Configures everything but the underlying operating system service. - `:delete` - Removes everything but the package and data_dir. - `:start` - Starts the underlying operating system service -- `:stop`- Stops the underlying operating system service +- `:stop`- Stops the underlying operating system service - `:restart` - Restarts the underlying operating system service - `:reload` - Reloads the underlying operating system service @@ -274,7 +268,7 @@ mysql_client 'default' do end ``` -#### Parameters +#### Properties - `package_name` - An array of packages to be installed. Defaults to a value looked up in an internal map. - `package_version` - Specific versions of the package to install, passed onto the underlying package manager. Defaults to `nil`. @@ -401,31 +395,16 @@ Or to connect over the network, use something like this: connect over the networ These network or socket ssettings can also be put in you $HOME/.my.cnf, if preferred. -### What about MariaDB, Percona, Drizzle, WebScaleSQL, etc. +### What about MariaDB, Percona, etc. MySQL forks are purposefully out of scope for this cookbook. This is mostly to reduce the testing matrix to a manageable size. Cookbooks for these technologies can easily be created by copying and adapting this cookbook. However, there will be differences. Package repository locations, package version names, software major version numbers, supported platform matrices, and the availability of software such as XtraDB and Galera are the main reasons that creating multiple cookbooks to make sense. -## Warnings - -## Hacking / Testing / TODO - -Please refer to the HACKING.md - -## License & Authors - -- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io)) -- Author:: AJ Christensen ([aj@chef.io](mailto:aj@chef.io)) -- Author:: Seth Chisamore ([schisamo@chef.io](mailto:schisamo@chef.io)) -- Author:: Brian Bianco ([brian.bianco@gmail.com](mailto:brian.bianco@gmail.com)) -- Author:: Jesse Howarth ([him@jessehowarth.com](mailto:him@jessehowarth.com)) -- Author:: Andrew Crump ([andrew@kotirisoftware.com](mailto:andrew@kotirisoftware.com)) -- Author:: Christoph Hartmann ([chris@lollyrock.com](mailto:chris@lollyrock.com)) -- Author:: Sean OMeara ([sean@chef.io](mailto:sean@chef.io)) +## License ```text -Copyright:: 2009-2014 Chef Software, Inc +Copyright:: 2009-2017 Chef Software, Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cookbooks/mysql/libraries/helpers.rb b/cookbooks/mysql/libraries/helpers.rb index 8b47559..72899fc 100644 --- a/cookbooks/mysql/libraries/helpers.rb +++ b/cookbooks/mysql/libraries/helpers.rb @@ -1,67 +1,118 @@ -require 'shellwords' - module MysqlCookbook - module Helpers - include Chef::DSL::IncludeRecipe + module HelpersBase + require 'shellwords' - def base_dir - prefix_dir || '/usr' + def el6? + return true if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 6 + false end - def configure_package_repositories - # we need to enable the yum-mysql-community repository to get packages - return unless %w(rhel fedora).include? node['platform_family'] - case parsed_version - when '5.5' - # Prefer packages from native repos - return if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 5 - return if node['platform_family'] == 'fedora' - include_recipe('yum-mysql-community::mysql55') - when '5.6' - include_recipe('yum-mysql-community::mysql56') - when '5.7' - include_recipe('yum-mysql-community::mysql57') - end + def el7? + return true if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 7 + false end - def client_package_name - return new_resource.package_name if new_resource.package_name - client_package + def wheezy? + return true if node['platform'] == 'debian' && node['platform_version'].to_i == 7 + false + end + + def jessie? + return true if node['platform'] == 'debian' && node['platform_version'].to_i == 8 + false + end + + def trusty? + return true if node['platform'] == 'ubuntu' && node['platform_version'] == '14.04' + return true if node['platform'] == 'linuxmint' && node['platform_version'] =~ /^17\.[0-9]$/ + false + end + + def xenial? + return true if node['platform'] == 'ubuntu' && node['platform_version'] == '16.04' + false end def defaults_file "#{etc_dir}/my.cnf" end - def error_log - return new_resource.error_log if new_resource.error_log + def default_data_dir + return "/var/lib/#{mysql_name}" if node['os'] == 'linux' + return "/opt/local/lib/#{mysql_name}" if node['os'] == 'solaris2' + return "/var/db/#{mysql_name}" if node['os'] == 'freebsd' + end + + def default_error_log "#{log_dir}/error.log" end - def etc_dir - return "/opt/mysql#{pkg_ver_string}/etc/#{mysql_name}" if node['platform_family'] == 'omnios' - return "#{prefix_dir}/etc/#{mysql_name}" if node['platform_family'] == 'smartos' - "#{prefix_dir}/etc/#{mysql_name}" + def default_pid_file + "#{run_dir}/mysqld.pid" end - def include_dir - "#{etc_dir}/conf.d" + def default_major_version + # rhelish + return '5.1' if el6? + return '5.6' if el7? + return '5.6' if node['platform'] == 'amazon' + + # debian + return '5.5' if wheezy? + return '5.5' if jessie? + + # ubuntu + return '5.5' if trusty? + return '5.7' if xenial? + + # misc + return '5.6' if node['platform'] == 'freebsd' + return '5.6' if node['platform'] == 'fedora' + return '5.6' if node['platform_family'] == 'suse' end - def lc_messages_dir - end - - def log_dir - return "/var/adm/log/#{mysql_name}" if node['platform_family'] == 'omnios' - "#{prefix_dir}/var/log/#{mysql_name}" + def major_from_full(v) + v.split('.').shift(2).join('.') end def mysql_name - "mysql-#{new_resource.instance}" + "mysql-#{instance}" end - def pkg_ver_string - parsed_version.delete('.') if node['platform_family'] == 'omnios' + def default_socket_file + "#{run_dir}/mysqld.sock" + end + + def default_client_package_name + return ['mysql', 'mysql-devel'] if major_version == '5.1' && el6? + return ['mysql55', 'mysql55-devel.x86_64'] if major_version == '5.5' && node['platform'] == 'amazon' + return ['mysql56', 'mysql56-devel.x86_64'] if major_version == '5.6' && node['platform'] == 'amazon' + return ['mysql-client-5.5', 'libmysqlclient-dev'] if major_version == '5.5' && node['platform_family'] == 'debian' + return ['mysql-client-5.6', 'libmysqlclient-dev'] if major_version == '5.6' && node['platform_family'] == 'debian' + return ['mysql-client-5.7', 'libmysqlclient-dev'] if major_version == '5.7' && node['platform_family'] == 'debian' + return 'mysql-community-server-client' if major_version == '5.6' && node['platform_family'] == 'suse' + ['mysql-community-client', 'mysql-community-devel'] + end + + def default_server_package_name + return 'mysql-server' if major_version == '5.1' && el6? + return 'mysql55-server' if major_version == '5.5' && node['platform'] == 'amazon' + return 'mysql56-server' if major_version == '5.6' && node['platform'] == 'amazon' + return 'mysql-server-5.5' if major_version == '5.5' && node['platform_family'] == 'debian' + return 'mysql-server-5.6' if major_version == '5.6' && node['platform_family'] == 'debian' + return 'mysql-server-5.7' if major_version == '5.7' && node['platform_family'] == 'debian' + return 'mysql-community-server' if major_version == '5.6' && node['platform_family'] == 'suse' + 'mysql-community-server' + end + + def socket_dir + File.dirname(socket) + end + + def run_dir + return "#{prefix_dir}/var/run/#{mysql_name}" if node['platform_family'] == 'rhel' + return "/run/#{mysql_name}" if node['platform_family'] == 'debian' + "/var/run/#{mysql_name}" end def prefix_dir @@ -72,102 +123,70 @@ module MysqlCookbook def scl_name return unless node['platform_family'] == 'rhel' - return 'mysql51' if parsed_version == '5.1' && node['platform_version'].to_i == 5 - return 'mysql55' if parsed_version == '5.5' && node['platform_version'].to_i == 5 + return 'mysql51' if version == '5.1' && node['platform_version'].to_i == 5 + return 'mysql55' if version == '5.5' && node['platform_version'].to_i == 5 end def scl_package? return unless node['platform_family'] == 'rhel' - return true if parsed_version == '5.1' && node['platform_version'].to_i == 5 - return true if parsed_version == '5.5' && node['platform_version'].to_i == 5 + return true if version == '5.1' && node['platform_version'].to_i == 5 + return true if version == '5.5' && node['platform_version'].to_i == 5 false end + def etc_dir + return "/opt/mysql#{pkg_ver_string}/etc/#{mysql_name}" if node['platform_family'] == 'omnios' + return "#{prefix_dir}/etc/#{mysql_name}" if node['platform_family'] == 'smartos' + "#{prefix_dir}/etc/#{mysql_name}" + end + + def base_dir + prefix_dir || '/usr' + end + def system_service_name return 'mysql51-mysqld' if node['platform_family'] == 'rhel' && scl_name == 'mysql51' return 'mysql55-mysqld' if node['platform_family'] == 'rhel' && scl_name == 'mysql55' return 'mysqld' if node['platform_family'] == 'rhel' return 'mysqld' if node['platform_family'] == 'fedora' - return 'mysql' if node['platform_family'] == 'debian' - return 'mysql' if node['platform_family'] == 'suse' - return 'mysql' if node['platform_family'] == 'omnios' - return 'mysql' if node['platform_family'] == 'smartos' + 'mysql' # not one of the above end def v56plus - return false if parsed_version.split('.')[0].to_i < 5 - return false if parsed_version.split('.')[1].to_i < 6 + return false if version.split('.')[0].to_i < 5 + return false if version.split('.')[1].to_i < 6 true end def v57plus - return false if parsed_version.split('.')[0].to_i < 5 - return false if parsed_version.split('.')[1].to_i < 7 + return false if version.split('.')[0].to_i < 5 + return false if version.split('.')[1].to_i < 7 true end - def password_column_name - return 'authentication_string' if v57plus - 'password' + def default_include_dir + "#{etc_dir}/conf.d" end - def password_expired - return ", password_expired='N'" if v57plus - '' + def log_dir + return "/var/adm/log/#{mysql_name}" if node['platform_family'] == 'omnios' + "#{prefix_dir}/var/log/#{mysql_name}" end - def root_password - if new_resource.initial_root_password == '' - Chef::Log.info('Root password is empty') - return '' - end - Shellwords.escape(new_resource.initial_root_password) - end - - # database and initial records - # initialization commands - - def mysqld_initialize_cmd - cmd = mysqld_bin - cmd << " --defaults-file=#{etc_dir}/my.cnf" - cmd << ' --initialize' - cmd << ' --explicit_defaults_for_timestamp' if v56plus - return "scl enable #{scl_name} \"#{cmd}\"" if scl_package? - cmd - end - - def mysql_install_db_cmd - cmd = mysql_install_db_bin - cmd << " --defaults-file=#{etc_dir}/my.cnf" - cmd << " --datadir=#{parsed_data_dir}" - cmd << ' --explicit_defaults_for_timestamp' if v56plus - return "scl enable #{scl_name} \"#{cmd}\"" if scl_package? - cmd - end - - def record_init - cmd = v56plus ? mysqld_bin : mysqld_safe_bin - cmd << " --defaults-file=#{etc_dir}/my.cnf" - cmd << " --init-file=/tmp/#{mysql_name}/my.sql" - cmd << ' --explicit_defaults_for_timestamp' if v56plus - cmd << ' &' - return "scl enable #{scl_name} \"#{cmd}\"" if scl_package? - cmd - end - - def db_init - return mysqld_initialize_cmd if v57plus - mysql_install_db_cmd - end + def lc_messages_dir; end def init_records_script + # Note: shell-escaping passwords in a SQL file may cause corruption - eg + # mysql will read \& as &, but \% as \%. Just escape bare-minimum \ and ' + sql_escaped_password = root_password.gsub('\\') { '\\\\' }.gsub("'") { '\\\'' } + <<-EOS set -e rm -rf /tmp/#{mysql_name} mkdir /tmp/#{mysql_name} - cat > /tmp/#{mysql_name}/my.sql <<-EOSQL -UPDATE mysql.user SET #{password_column_name}=PASSWORD('#{root_password}')#{password_expired} WHERE user = 'root'; + cat > /tmp/#{mysql_name}/my.sql <<-'EOSQL' +UPDATE mysql.user SET #{password_column_name}=PASSWORD('#{sql_escaped_password}')#{password_expired} WHERE user = 'root'; DELETE FROM mysql.user WHERE USER LIKE ''; DELETE FROM mysql.user WHERE user = 'root' and host NOT IN ('127.0.0.1', 'localhost'); FLUSH PRIVILEGES; @@ -185,10 +204,27 @@ EOSQL EOS end - def mysql_bin - return "#{prefix_dir}/bin/mysql" if node['platform_family'] == 'smartos' - return "#{base_dir}/bin/mysql" if node['platform_family'] == 'omnios' - "#{prefix_dir}/usr/bin/mysql" + def password_column_name + return 'authentication_string' if v57plus + 'password' + end + + def root_password + if initial_root_password == '' + Chef::Log.info('Root password is empty') + return '' + end + initial_root_password + end + + def password_expired + return ", password_expired='N'" if v57plus + '' + end + + def db_init + return mysqld_initialize_cmd if v57plus + mysql_install_db_cmd end def mysql_install_db_bin @@ -197,8 +233,13 @@ EOSQL 'mysql_install_db' end - def mysql_version - new_resource.version + def mysql_install_db_cmd + cmd = mysql_install_db_bin + cmd << " --defaults-file=#{etc_dir}/my.cnf" + cmd << " --datadir=#{data_dir}" + cmd << ' --explicit_defaults_for_timestamp' if v56plus && !v57plus + return "scl enable #{scl_name} \"#{cmd}\"" if scl_package? + cmd end def mysqladmin_bin @@ -216,6 +257,15 @@ EOSQL "#{prefix_dir}/usr/sbin/mysqld" end + def mysqld_initialize_cmd + cmd = mysqld_bin + cmd << " --defaults-file=#{etc_dir}/my.cnf" + cmd << ' --initialize' + cmd << ' --explicit_defaults_for_timestamp' if v56plus + return "scl enable #{scl_name} \"#{cmd}\"" if scl_package? + cmd + end + def mysqld_safe_bin return "#{prefix_dir}/bin/mysqld_safe" if node['platform_family'] == 'smartos' return "#{base_dir}/bin/mysqld_safe" if node['platform_family'] == 'omnios' @@ -223,248 +273,14 @@ EOSQL "#{prefix_dir}/usr/bin/mysqld_safe" end - def pid_file - return new_resource.pid_file if new_resource.pid_file - "#{run_dir}/mysqld.pid" - end - - def run_dir - return "#{prefix_dir}/var/run/#{mysql_name}" if node['platform_family'] == 'rhel' - return "/run/#{mysql_name}" if node['platform_family'] == 'debian' - "/var/run/#{mysql_name}" - end - - def sensitive_supported? - Gem::Version.new(Chef::VERSION) >= Gem::Version.new('11.14.0') - end - - def socket_file - return new_resource.socket if new_resource.socket - "#{run_dir}/mysqld.sock" - end - - def socket_dir - return File.dirname(new_resource.socket) if new_resource.socket - run_dir - end - - def tmp_dir - return new_resource.tmp_dir if new_resource.tmp_dir - '/tmp' - end - - ####### - # FIXME: There is a LOT of duplication here.. - # There has to be a less gnarly way to look up this information. Refactor for great good! - ####### - class Pkginfo - def self.pkginfo - # Autovivification is Perl. - @pkginfo = Chef::Node.new - - @pkginfo.set['debian']['10.04']['5.1']['client_package'] = %w(mysql-client-5.1 libmysqlclient-dev) - @pkginfo.set['debian']['10.04']['5.1']['server_package'] = 'mysql-server-5.1' - @pkginfo.set['debian']['12.04']['5.5']['client_package'] = %w(mysql-client-5.5 libmysqlclient-dev) - @pkginfo.set['debian']['12.04']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['debian']['13.04']['5.5']['client_package'] = %w(mysql-client-5.5 libmysqlclient-dev) - @pkginfo.set['debian']['13.04']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['debian']['13.10']['5.5']['client_package'] = %w(mysql-client-5.5 libmysqlclient-dev) - @pkginfo.set['debian']['13.10']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['debian']['14.04']['5.5']['client_package'] = %w(mysql-client-5.5 libmysqlclient-dev) - @pkginfo.set['debian']['14.04']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['debian']['14.04']['5.6']['client_package'] = %w(mysql-client-5.6 libmysqlclient-dev) - @pkginfo.set['debian']['14.04']['5.6']['server_package'] = 'mysql-server-5.6' - @pkginfo.set['debian']['14.10']['5.5']['client_package'] = %w(mysql-client-5.5 libmysqlclient-dev) - @pkginfo.set['debian']['14.10']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['debian']['14.10']['5.6']['client_package'] = %w(mysql-client-5.6 libmysqlclient-dev) - @pkginfo.set['debian']['14.10']['5.6']['server_package'] = 'mysql-server-5.6' - @pkginfo.set['debian']['15.04']['5.6']['client_package'] = %w(mysql-client-5.6 libmysqlclient-dev) - @pkginfo.set['debian']['15.04']['5.6']['server_package'] = 'mysql-server-5.6' - @pkginfo.set['debian']['15.10']['5.6']['client_package'] = %w(mysql-client-5.6 libmysqlclient-dev) - @pkginfo.set['debian']['15.10']['5.6']['server_package'] = 'mysql-server-5.6' - @pkginfo.set['debian']['6']['5.1']['client_package'] = %w(mysql-client libmysqlclient-dev) - @pkginfo.set['debian']['6']['5.1']['server_package'] = 'mysql-server-5.1' - @pkginfo.set['debian']['7']['5.5']['client_package'] = %w(mysql-client libmysqlclient-dev) - @pkginfo.set['debian']['7']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['debian']['7']['5.6']['client_package'] = %w(mysql-client libmysqlclient-dev) # apt-repo from dotdeb - @pkginfo.set['debian']['7']['5.6']['server_package'] = 'mysql-server-5.6' - @pkginfo.set['debian']['7']['5.7']['client_package'] = %w(mysql-client libmysqlclient-dev) # apt-repo from dotdeb - @pkginfo.set['debian']['7']['5.7']['server_package'] = 'mysql-server-5.7' - @pkginfo.set['debian']['8']['5.5']['client_package'] = %w(mysql-client libmysqlclient-dev) - @pkginfo.set['debian']['8']['5.5']['server_package'] = 'mysql-server-5.5' - @pkginfo.set['fedora']['20']['5.5']['client_package'] = %w(community-mysql community-mysql-devel) - @pkginfo.set['fedora']['20']['5.5']['server_package'] = 'community-mysql-server' - @pkginfo.set['fedora']['20']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['fedora']['20']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['fedora']['20']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['fedora']['20']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['fedora']['21']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['fedora']['21']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['fedora']['21']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['fedora']['21']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['fedora']['22']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['fedora']['22']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['fedora']['22']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['fedora']['22']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['freebsd']['10']['5.5']['client_package'] = %w(mysql55-client) - @pkginfo.set['freebsd']['10']['5.5']['server_package'] = 'mysql55-server' - @pkginfo.set['freebsd']['9']['5.5']['client_package'] = %w(mysql55-client) - @pkginfo.set['freebsd']['9']['5.5']['server_package'] = 'mysql55-server' - @pkginfo.set['omnios']['151006']['5.5']['client_package'] = %w(database/mysql-55/library) - @pkginfo.set['omnios']['151006']['5.5']['server_package'] = 'database/mysql-55' - @pkginfo.set['omnios']['151006']['5.6']['client_package'] = %w(database/mysql-56) - @pkginfo.set['omnios']['151006']['5.6']['server_package'] = 'database/mysql-56' - @pkginfo.set['rhel']['2014.09']['5.1']['server_package'] = %w(mysql51 mysql51-devel) - @pkginfo.set['rhel']['2014.09']['5.1']['server_package'] = 'mysql51-server' - @pkginfo.set['rhel']['2014.09']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2014.09']['5.5']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2014.09']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2014.09']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2014.09']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2014.09']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2015.03']['5.1']['server_package'] = %w(mysql51 mysql51-devel) - @pkginfo.set['rhel']['2015.03']['5.1']['server_package'] = 'mysql51-server' - @pkginfo.set['rhel']['2015.03']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2015.03']['5.5']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2015.03']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2015.03']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2015.03']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2015.03']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2015.09']['5.1']['server_package'] = %w(mysql51 mysql51-devel) - @pkginfo.set['rhel']['2015.09']['5.1']['server_package'] = 'mysql51-server' - @pkginfo.set['rhel']['2015.09']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2015.09']['5.5']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2015.09']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2015.09']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2015.09']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2015.09']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2016.03']['5.1']['server_package'] = %w(mysql51 mysql51-devel) - @pkginfo.set['rhel']['2016.03']['5.1']['server_package'] = 'mysql51-server' - @pkginfo.set['rhel']['2016.03']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2016.03']['5.5']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2016.03']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2016.03']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['2016.03']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['2016.03']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['5']['5.0']['client_package'] = %w(mysql mysql-devel) - @pkginfo.set['rhel']['5']['5.0']['server_package'] = 'mysql-server' - @pkginfo.set['rhel']['5']['5.1']['client_package'] = %w(mysql51-mysql) - @pkginfo.set['rhel']['5']['5.1']['server_package'] = 'mysql51-mysql-server' - @pkginfo.set['rhel']['5']['5.5']['client_package'] = %w(mysql55-mysql mysql55-mysql-devel) - @pkginfo.set['rhel']['5']['5.5']['server_package'] = 'mysql55-mysql-server' - @pkginfo.set['rhel']['5']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['5']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['5']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['5']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['6']['5.1']['client_package'] = %w(mysql mysql-devel) - @pkginfo.set['rhel']['6']['5.1']['server_package'] = 'mysql-server' - @pkginfo.set['rhel']['6']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['6']['5.5']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['6']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['6']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['6']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['6']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['7']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['7']['5.5']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['7']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['7']['5.6']['server_package'] = 'mysql-community-server' - @pkginfo.set['rhel']['7']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel) - @pkginfo.set['rhel']['7']['5.7']['server_package'] = 'mysql-community-server' - @pkginfo.set['smartos']['5.11']['5.5']['client_package'] = %w(mysql-client) - @pkginfo.set['smartos']['5.11']['5.5']['server_package'] = 'mysql-server' - @pkginfo.set['smartos']['5.11']['5.6']['client_package'] = %w(mysql-client) - @pkginfo.set['smartos']['5.11']['5.6']['server_package'] = 'mysql-server' - @pkginfo.set['suse']['11.3']['5.5']['client_package'] = %w(mysql-client) - @pkginfo.set['suse']['11.3']['5.5']['server_package'] = 'mysql' - @pkginfo.set['suse']['12.0']['5.5']['client_package'] = %w(mysql-client) - @pkginfo.set['suse']['12.0']['5.5']['server_package'] = 'mysql' - - @pkginfo - end - end - - def package_name_for(platform, platform_family, platform_version, version, type) - keyname = keyname_for(platform, platform_family, platform_version) - info = Pkginfo.pkginfo[platform_family.to_sym][keyname] - type_label = type.to_s.gsub('_package', '').capitalize - unless info[version] - # Show availabe versions if the requested is not available on the current platform - Chef::Log.error("Unsupported Version: You requested to install a Mysql #{type_label} version that is not supported by your platform") - Chef::Log.error("Platform: #{platform_family} #{platform_version} - Request Mysql #{type_label} version: #{version}") - Chef::Log.error("Availabe versions for your platform are: #{info.map { |k, _v| k }.join(' - ')}") - raise "Unsupported Mysql #{type_label} Version" - end - info[version][type] - end - - def keyname_for(platform, platform_family, platform_version) - return platform_version if platform_family == 'debian' && platform == 'ubuntu' - return platform_version if platform_family == 'fedora' - return platform_version if platform_family == 'omnios' - return platform_version if platform_family == 'rhel' && platform == 'amazon' - return platform_version if platform_family == 'smartos' - return platform_version if platform_family == 'suse' - return platform_version.to_i.to_s if platform_family == 'debian' - return platform_version.to_i.to_s if platform_family == 'rhel' - return platform_version.to_s if platform_family == 'debian' && platform_version =~ /sid$/ - return platform_version.to_s if platform_family == 'freebsd' - end - - def parsed_data_dir - return new_resource.data_dir if new_resource.data_dir - return "/opt/local/lib/#{mysql_name}" if node['os'] == 'solaris2' - return "/var/lib/#{mysql_name}" if node['os'] == 'linux' - return "/var/db/#{mysql_name}" if node['os'] == 'freebsd' - end - - def client_package - package_name_for( - node['platform'], - node['platform_family'], - node['platform_version'], - parsed_version, - :client_package - ) - end - - def server_package - package_name_for( - node['platform'], - node['platform_family'], - node['platform_version'], - parsed_version, - :server_package - ) - end - - def server_package_name - return new_resource.package_name if new_resource.package_name - server_package - end - - def parsed_version - return new_resource.version if new_resource.version - return '5.0' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 5 - return '5.1' if node['platform_family'] == 'debian' && node['platform_version'] == '10.04' - return '5.1' if node['platform_family'] == 'debian' && node['platform_version'].to_i == 6 - return '5.1' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 6 - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'] == '12.04' - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'] == '13.04' - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'] == '13.10' - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'] == '14.04' - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'] == '14.10' - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'].to_i == 7 - return '5.5' if node['platform_family'] == 'debian' && node['platform_version'].to_i == 8 - return '5.5' if node['platform_family'] == 'freebsd' - return '5.5' if node['platform_family'] == 'omnios' - return '5.5' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 2014 - return '5.5' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 2015 - return '5.5' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 7 - return '5.5' if node['platform_family'] == 'smartos' - return '5.5' if node['platform_family'] == 'suse' - return '5.6' if node['platform_family'] == 'fedora' - return '5.6' if node['platform_family'] == 'debian' && node['platform_version'] == '15.04' - return '5.6' if node['platform_family'] == 'debian' && node['platform_version'] == '15.10' + def record_init + cmd = v56plus ? mysqld_bin : mysqld_safe_bin + cmd << " --defaults-file=#{etc_dir}/my.cnf" + cmd << " --init-file=/tmp/#{mysql_name}/my.sql" + cmd << ' --explicit_defaults_for_timestamp' if v56plus + cmd << ' &' + return "scl enable #{scl_name} \"#{cmd}\"" if scl_package? + cmd end end end diff --git a/cookbooks/mysql/libraries/matchers.rb b/cookbooks/mysql/libraries/matchers.rb index 373e3cb..adf5e73 100644 --- a/cookbooks/mysql/libraries/matchers.rb +++ b/cookbooks/mysql/libraries/matchers.rb @@ -1,18 +1,40 @@ if defined?(ChefSpec) - if ChefSpec.respond_to?(:define_matcher) - # ChefSpec >= 4.1 - ChefSpec.define_matcher :mysql_config - ChefSpec.define_matcher :mysql_service - ChefSpec.define_matcher :mysql_client - elsif defined?(ChefSpec::Runner) && - ChefSpec::Runner.respond_to?(:define_runner_method) - # ChefSpec < 4.1 - ChefSpec::Runner.define_runner_method :mysql_config - ChefSpec::Runner.define_runner_method :mysql_service - ChefSpec::Runner.define_runner_method :mysql_client + ChefSpec.define_matcher :mysql_config + ChefSpec.define_matcher :mysql_service + ChefSpec.define_matcher :mysql_client + + # mysql_client_client_installation_package + def install_mysql_client_installation_package(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_client_installation_package, :create, resource_name) end - # config + def remove_mysql_client_installation_package(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_client_installation_package, :remove, resource_name) + end + + # mysql_server_server_installation_package + def install_mysql_server_installation_package(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_server_installation_package, :install, resource_name) + end + + def remove_mysql_server_installation_package(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_server_installation_package, :remove, resource_name) + end + + ##### + # old + ##### + + # client + def create_mysql_client(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_client, :create, resource_name) + end + + def delete_mysql_client(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:mysql_client, :delete, resource_name) + end + + # mysql_config def create_mysql_config(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:mysql_config, :create, resource_name) end @@ -46,12 +68,4 @@ if defined?(ChefSpec) ChefSpec::Matchers::ResourceMatcher.new(:mysql_service, :reload, resource_name) end - # client - def create_mysql_client(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:mysql_client, :create, resource_name) - end - - def delete_mysql_client(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:mysql_client, :delete, resource_name) - end end diff --git a/cookbooks/mysql/libraries/mysql_base.rb b/cookbooks/mysql/libraries/mysql_base.rb new file mode 100644 index 0000000..b04a129 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_base.rb @@ -0,0 +1,30 @@ +module MysqlCookbook + class MysqlBase < Chef::Resource + require_relative 'helpers' + + # All resources are composites + def whyrun_supported? + true + end + + ################ + # Type Constants + ################ + + Boolean = property_type( + is: [true, false], + default: false + ) unless defined?(Boolean) + + ################### + # Common Properties + ################### + property :run_group, String, default: 'mysql', desired_state: false + property :run_user, String, default: 'mysql', desired_state: false + property :version, String, default: lazy { default_major_version }, desired_state: false + property :include_dir, String, default: lazy { default_include_dir }, desired_state: false + property :major_version, String, default: lazy { major_from_full(version) }, desired_state: false + + declare_action_class + end +end diff --git a/cookbooks/mysql/libraries/mysql_client_installation_package.rb b/cookbooks/mysql/libraries/mysql_client_installation_package.rb new file mode 100644 index 0000000..1e1d946 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_client_installation_package.rb @@ -0,0 +1,31 @@ +module MysqlCookbook + class MysqlClientInstallationPackage < MysqlBase + # helper methods + require_relative 'helpers' + include MysqlCookbook::HelpersBase + + # Resource properties + resource_name :mysql_client_installation_package + provides :mysql_client_installation, os: 'linux' + provides :mysql_client, os: 'linux' + + property :package_name, [String, Array], default: lazy { default_client_package_name }, desired_state: false + property :package_options, [String, nil], desired_state: false + property :package_version, [String, nil], default: nil, desired_state: false + + # Actions + action :create do + package package_name do + version package_version if package_version + options package_options if package_options + action :install + end + end + + action :delete do + package package_name do + action :remove + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_config.rb b/cookbooks/mysql/libraries/mysql_config.rb new file mode 100644 index 0000000..be5eee0 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_config.rb @@ -0,0 +1,56 @@ +module MysqlCookbook + class MysqlConfig < MysqlBase + resource_name :mysql_config + + property :config_name, String, name_property: true, desired_state: false + property :cookbook, String, desired_state: false + property :group, String, default: 'mysql', desired_state: false + property :instance, String, default: 'default', desired_state: false + property :owner, String, default: 'mysql', desired_state: false + property :source, String, desired_state: false + property :variables, [Hash], desired_state: false + property :version, String, default: lazy { default_major_version }, desired_state: false + + require_relative 'helpers' + include MysqlCookbook::HelpersBase + + provides :mysql_config + + action :create do + # hax because group property + g = Chef::Resource::Group.new(new_resource.group, run_context) + g.system true if name == 'mysql' + resource_collection.insert g + + user owner do + gid owner + system true if name == 'mysql' + action :create + end + + directory include_dir do + owner new_resource.owner + group new_resource.group + mode '0750' + recursive true + action :create + end + + template "#{include_dir}/#{config_name}.cnf" do + owner new_resource.owner + group new_resource.group + mode '0640' + variables(new_resource.variables) + source new_resource.source + cookbook new_resource.cookbook + action :create + end + end + + action :delete do + file "#{include_dir}/#{config_name}.cnf" do + action :delete + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_server_installation_package.rb b/cookbooks/mysql/libraries/mysql_server_installation_package.rb new file mode 100644 index 0000000..385e202 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_server_installation_package.rb @@ -0,0 +1,42 @@ +module MysqlCookbook + class MysqlServerInstallationPackage < MysqlBase + # Resource properties + resource_name :mysql_server_installation_package + provides :mysql_server_installation, os: 'linux' + + property :package_name, String, default: lazy { default_server_package_name }, desired_state: false + property :package_options, [String, nil], desired_state: false + property :package_version, [String, nil], default: nil, desired_state: false + + # helper methods + require_relative 'helpers' + include MysqlCookbook::HelpersBase + + # Actions + action :install do + package package_name do + version package_version if package_version + options package_options if package_options + notifies :install, 'package[perl-Sys-Hostname-Long]', :immediately if platform_family?('suse') + notifies :run, 'execute[Initial DB setup script]', :immediately if platform_family?('suse') + action :install + end + + package 'perl-Sys-Hostname-Long' do + action :nothing + end + + execute 'Initial DB setup script' do + environment 'INSTANCE' => new_resource.name + command '/usr/lib/mysql/mysql-systemd-helper install' + action :nothing + end + end + + action :delete do + package package_name do + action :remove + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_service.rb b/cookbooks/mysql/libraries/mysql_service.rb new file mode 100644 index 0000000..80fb7c3 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_service.rb @@ -0,0 +1,105 @@ +module MysqlCookbook + require_relative 'mysql_service_base' + class MysqlService < MysqlServiceBase + resource_name :mysql_service + + # installation type and service_manager + property :install_method, %w(package auto), default: 'auto', desired_state: false + property :service_manager, %w(sysvinit upstart systemd auto), default: 'auto', desired_state: false + + # mysql_server_installation + property :version, String, default: lazy { default_major_version }, desired_state: false + property :major_version, String, default: lazy { major_from_full(version) }, desired_state: false + property :package_name, String, default: lazy { default_package_name }, desired_state: false + property :package_options, [String, nil], desired_state: false + property :package_version, [String, nil], default: nil, desired_state: false + + ################ + # Helper Methods + ################ + + def copy_properties_to(to, *properties) + properties = self.class.properties.keys if properties.empty? + properties.each do |p| + # If the property is set on from, and exists on to, set the + # property on to + if to.class.properties.include?(p) && property_is_set?(p) + to.send(p, send(p)) + end + end + end + + action_class.class_eval do + def installation(&block) + case install_method + when 'auto' + install = mysql_server_installation(name, &block) + when 'package' + install = mysql_server_installation_package(name, &block) + when 'none' + Chef::Log.info('Skipping MySQL installation. Assuming it was handled previously.') + return + end + copy_properties_to(install) + install + end + + def svc_manager(&block) + case service_manager + when 'auto' + svc = mysql_service_manager(name, &block) + when 'sysvinit' + svc = mysql_service_manager_sysvinit(name, &block) + when 'upstart' + svc = mysql_service_manager_upstart(name, &block) + when 'systemd' + svc = mysql_service_manager_systemd(name, &block) + end + copy_properties_to(svc) + svc + end + end + + ######### + # Actions + ######### + + action :create do + installation do + action :install + end + + svc_manager do + action :create + end + end + + action :start do + svc_manager do + action :start + end + end + + action :delete do + svc_manager do + action :delete + end + + installation do + action :delete + end + end + + action :restart do + svc_manager do + action :restart + end + end + + action :stop do + svc_manager do + action :stop + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_service_base.rb b/cookbooks/mysql/libraries/mysql_service_base.rb new file mode 100644 index 0000000..01f26c7 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_service_base.rb @@ -0,0 +1,203 @@ +module MysqlCookbook + class MysqlServiceBase < MysqlBase + property :bind_address, String, desired_state: false + property :charset, String, default: 'utf8', desired_state: false + property :data_dir, String, default: lazy { default_data_dir }, desired_state: false + property :error_log, String, default: lazy { default_error_log }, desired_state: false + property :initial_root_password, String, default: 'ilikerandompasswords', desired_state: false + property :instance, String, name_property: true, desired_state: false + property :mysqld_options, Hash, default: {}, desired_state: false + property :pid_file, String, default: lazy { default_pid_file }, desired_state: false + property :port, [String, Integer], default: '3306', desired_state: false + property :socket, String, default: lazy { default_socket_file }, desired_state: false + property :tmp_dir, String, desired_state: false + + alias socket_file socket + + require_relative 'helpers' + include MysqlCookbook::HelpersBase + + # action class methods are available within the actions and work as if the coded + # was inline the action. No messing with classes or passing in the new_resource + declare_action_class.class_eval do + def create_system_user + group 'mysql' do + action :create + end + + user 'mysql' do + gid 'mysql' + action :create + end + end + + def create_config + # require 'pry' ; binding.pry + + # Yak shaving secion. Account for random errata. + # + # Turns out that mysqld is hard coded to try and read + # /etc/mysql/my.cnf, and its presence causes problems when + # setting up multiple services. + file "#{prefix_dir}/etc/mysql/my.cnf" do + action :delete + end + + file "#{prefix_dir}/etc/my.cnf" do + action :delete + end + + # mysql_install_db is broken on 5.6.13 + link "#{prefix_dir}/usr/share/my-default.cnf" do + to "#{etc_dir}/my.cnf" + not_if { ::File.exist? "#{prefix_dir}/usr/share/my-default.cnf" } # FIXME: Chef bug? + action :create + end + + # Support directories + directory etc_dir do + owner run_user + group run_group + mode '0750' + recursive true + action :create + end + + directory include_dir do + owner run_user + group run_group + mode '0750' + recursive true + action :create + end + + directory run_dir do + owner run_user + group run_group + mode '0755' + recursive true + action :create + end + + directory log_dir do + owner run_user + group run_group + mode '0750' + recursive true + action :create + end + + directory data_dir do + owner run_user + group run_group + mode '0750' + recursive true + action :create + end + + # Main configuration file + template "#{etc_dir}/my.cnf" do + source 'my.cnf.erb' + cookbook 'mysql' + owner run_user + group run_group + mode '0600' + variables(config: new_resource) + action :create + end + end + + def initialize_database + # initialize database and create initial records + bash "#{name} initial records" do + code init_records_script + umask '022' + returns [0, 1, 2] # facepalm + not_if "/usr/bin/test -f #{data_dir}/mysql/user.frm" + action :run + end + end + + def delete_support_directories + # Stop the service before removing support directories + delete_stop_service + + directory etc_dir do + recursive true + action :delete + end + + directory run_dir do + recursive true + action :delete + end + + directory log_dir do + recursive true + action :delete + end + end + + # + # Platform specific bits + # + def configure_apparmor + # Do not add these resource if inside a container + # Only valid on Ubuntu + return if ::File.exist?('/.dockerenv') || ::File.exist?('/.dockerinit') || node['platform'] != 'ubuntu' + + # Apparmor + package 'apparmor' do + action :install + end + + directory '/etc/apparmor.d/local/mysql' do + owner 'root' + group 'root' + mode '0755' + recursive true + action :create + end + + template '/etc/apparmor.d/local/usr.sbin.mysqld' do + cookbook 'mysql' + source 'apparmor/usr.sbin.mysqld-local.erb' + owner 'root' + group 'root' + mode '0644' + action :create + notifies :restart, "service[#{instance} apparmor]", :immediately + end + + template '/etc/apparmor.d/usr.sbin.mysqld' do + cookbook 'mysql' + source 'apparmor/usr.sbin.mysqld.erb' + owner 'root' + group 'root' + mode '0644' + action :create + notifies :restart, "service[#{instance} apparmor]", :immediately + end + + template "/etc/apparmor.d/local/mysql/#{instance}" do + cookbook 'mysql' + source 'apparmor/usr.sbin.mysqld-instance.erb' + owner 'root' + group 'root' + mode '0644' + variables( + config: new_resource, + mysql_name: mysql_name + ) + action :create + notifies :restart, "service[#{instance} apparmor]", :immediately + end + + service "#{instance} apparmor" do + service_name 'apparmor' + action :nothing + end + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_service_manager_systemd.rb b/cookbooks/mysql/libraries/mysql_service_manager_systemd.rb new file mode 100644 index 0000000..e18fe74 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_service_manager_systemd.rb @@ -0,0 +1,142 @@ +module MysqlCookbook + class MysqlServiceManagerSystemd < MysqlServiceBase + resource_name :mysql_service_manager_systemd + + provides :mysql_service_manager, os: 'linux' do |_node| + Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd) + end + + action :create do + # from base + create_system_user + stop_system_service + create_config + configure_apparmor + initialize_database + end + + action :start do + # Needed for Debian / Ubuntu + directory '/usr/libexec' do + owner 'root' + group 'root' + mode '0755' + action :create + end + + # this script is called by the main systemd unit file, and + # spins around until the service is actually up and running. + template "/usr/libexec/#{mysql_name}-wait-ready" do + path "/usr/libexec/#{mysql_name}-wait-ready" + source 'systemd/mysqld-wait-ready.erb' + owner 'root' + group 'root' + mode '0755' + variables(socket_file: socket_file) + cookbook 'mysql' + action :create + end + + # this is the main systemd unit file + template "/etc/systemd/system/#{mysql_name}.service" do + path "/etc/systemd/system/#{mysql_name}.service" + source 'systemd/mysqld.service.erb' + owner 'root' + group 'root' + mode '0644' + variables( + config: new_resource, + etc_dir: etc_dir, + base_dir: base_dir, + mysqld_bin: mysqld_bin + ) + cookbook 'mysql' + notifies :run, "execute[#{instance} systemctl daemon-reload]", :immediately + action :create + end + + # avoid 'Unit file changed on disk' warning + execute "#{instance} systemctl daemon-reload" do + command '/bin/systemctl daemon-reload' + action :nothing + end + + # tmpfiles.d config so the service survives reboot + template "/usr/lib/tmpfiles.d/#{mysql_name}.conf" do + path "/usr/lib/tmpfiles.d/#{mysql_name}.conf" + source 'tmpfiles.d.conf.erb' + owner 'root' + group 'root' + mode '0644' + variables( + run_dir: run_dir, + run_user: run_user, + run_group: run_group + ) + cookbook 'mysql' + action :create + end + + # service management resource + service mysql_name.to_s do + service_name mysql_name + provider Chef::Provider::Service::Systemd + supports restart: true, status: true + action [:enable, :start] + end + end + + action :stop do + # service management resource + service mysql_name.to_s do + service_name mysql_name + provider Chef::Provider::Service::Systemd + supports status: true + action [:disable, :stop] + only_if { ::File.exist?("/usr/lib/systemd/system/#{mysql_name}.service") } + end + end + + action :restart do + # service management resource + service mysql_name.to_s do + service_name mysql_name + provider Chef::Provider::Service::Systemd + supports restart: true + action :restart + end + end + + action :reload do + # service management resource + service mysql_name.to_s do + service_name mysql_name + provider Chef::Provider::Service::Systemd + action :reload + end + end + + declare_action_class.class_eval do + def stop_system_service + # service management resource + service 'mysql' do + service_name system_service_name + provider Chef::Provider::Service::Systemd + supports status: true + action [:stop, :disable] + end + end + + def delete_stop_service + # service management resource + service mysql_name.to_s do + service_name mysql_name + provider Chef::Provider::Service::Systemd + supports status: true + action [:disable, :stop] + only_if { ::File.exist?("/usr/lib/systemd/system/#{mysql_name}.service") } + end + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_service_manager_sysvinit.rb b/cookbooks/mysql/libraries/mysql_service_manager_sysvinit.rb new file mode 100644 index 0000000..1b76064 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_service_manager_sysvinit.rb @@ -0,0 +1,79 @@ +module MysqlCookbook + class MysqlServiceManagerSysvinit < MysqlServiceBase + resource_name :mysql_service_manager_sysvinit + + provides :mysql_service_manager, os: 'linux' + + action :create do + # from base + create_system_user + stop_system_service + create_config + initialize_database + configure_apparmor + end + + action :start do + template "/etc/init.d/#{mysql_name}" do + source 'sysvinit/mysqld.erb' + owner 'root' + group 'root' + mode '0755' + variables( + config: new_resource, + defaults_file: defaults_file, + error_log: error_log, + mysql_name: mysql_name, + mysqladmin_bin: mysqladmin_bin, + mysqld_safe_bin: mysqld_safe_bin, + pid_file: pid_file, + scl_name: scl_name + ) + cookbook 'mysql' + action :create + end + + service mysql_name do + supports restart: true, status: true + action [:enable, :start] + end + end + + action :stop do + service mysql_name do + supports restart: true, status: true + action [:stop] + end + end + + action :restart do + service mysql_name do + supports restart: true + action :restart + end + end + + action :reload do + service mysql_name do + action :reload + end + end + + declare_action_class.class_eval do + def stop_system_service + service system_service_name do + supports status: true + action [:stop, :disable] + end + end + + def delete_stop_service + service mysql_name do + supports status: true + action [:disable, :stop] + only_if { ::File.exist?("#{etc_dir}/init.d/#{mysql_name}") } + end + end + end + end +end diff --git a/cookbooks/mysql/libraries/mysql_service_manager_upstart.rb b/cookbooks/mysql/libraries/mysql_service_manager_upstart.rb new file mode 100644 index 0000000..90d4172 --- /dev/null +++ b/cookbooks/mysql/libraries/mysql_service_manager_upstart.rb @@ -0,0 +1,103 @@ +module MysqlCookbook + class MysqlServiceManagerUpstart < MysqlServiceBase + resource_name :mysql_service_manager_upstart + + provides :mysql_service_manager, platform_family: 'debian' do |_node| + Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) && + !Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd) && + !Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat) && + ::File.exist?('/sbin/status') # Fix for Docker, in 7 and 8 images /sbin/status doesn't exists and Upstart provider doesn't work + end + + action :create do + # from base + create_system_user + stop_system_service + create_config + configure_apparmor + initialize_database + end + + action :start do + template "/usr/sbin/#{mysql_name}-wait-ready" do + source 'upstart/mysqld-wait-ready.erb' + owner 'root' + group 'root' + mode '0755' + variables(socket_file: socket_file) + cookbook 'mysql' + action :create + end + + template "/etc/init/#{mysql_name}.conf" do + source 'upstart/mysqld.erb' + owner 'root' + group 'root' + mode '0644' + variables( + defaults_file: defaults_file, + mysql_name: mysql_name, + run_group: run_group, + run_user: run_user, + socket_dir: socket_dir + ) + cookbook 'mysql' + action :create + end + + service mysql_name do + provider Chef::Provider::Service::Upstart + supports status: true + action [:start] + end + end + + action :stop do + service mysql_name do + provider Chef::Provider::Service::Upstart + supports restart: true, status: true + action [:stop] + end + end + + action :restart do + # With Upstart, restarting the service doesn't behave "as expected". + # We want the post-start stanzas, which wait until the + # service is available before returning + # + # http://upstart.ubuntu.com/cookbook/#restart + service mysql_name do + provider Chef::Provider::Service::Upstart + action [:stop, :start] + end + end + + action :reload do + # With Upstart, reload just sends a HUP signal to the process. + # As far as I can tell, this doesn't work the way it's + # supposed to, so we need to actually restart the service. + service mysql_name do + provider Chef::Provider::Service::Upstart + action [:stop, :start] + end + end + + declare_action_class.class_eval do + def stop_system_service + service system_service_name do + provider Chef::Provider::Service::Upstart + supports status: true + action [:stop, :disable] + end + end + + def delete_stop_service + service mysql_name do + provider Chef::Provider::Service::Upstart + action [:disable, :stop] + only_if { ::File.exist?("#{etc_dir}/init/#{mysql_name}") } + end + end + end + end +end diff --git a/cookbooks/mysql/libraries/provider_mysql_client.rb b/cookbooks/mysql/libraries/provider_mysql_client.rb deleted file mode 100644 index c796d11..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_client.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'chef/provider/lwrp_base' -require_relative 'helpers' - -class Chef - class Provider - class MysqlClient < Chef::Provider::LWRPBase - include MysqlCookbook::Helpers - provides :mysql_client if defined?(provides) - - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - action :create do - # From helpers.rb - configure_package_repositories - - client_package_name.each do |p| - package "#{new_resource.name} :create #{p}" do - package_name p - version new_resource.version if node['platform'] == 'smartos' - version new_resource.package_version - action :install - end - end - end - - action :delete do - parsed_package_name.each do |p| - package "#{new_resource.name} :delete #{p}" do - action :remove - end - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_mysql_config.rb b/cookbooks/mysql/libraries/provider_mysql_config.rb deleted file mode 100644 index 3732c1c..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_config.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'chef/provider/lwrp_base' -require_relative 'helpers' - -class Chef - class Provider - class MysqlConfig < Chef::Provider::LWRPBase - include MysqlCookbook::Helpers - provides :mysql_config if defined?(provides) - - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - action :create do - group "#{new_resource.name} :create #{new_resource.group}" do - group_name new_resource.group - system true if new_resource.name == 'mysql' - action :create - end - - user "#{new_resource.name} :create #{new_resource.owner}" do - username new_resource.owner - gid new_resource.owner - system true if new_resource.name == 'mysql' - action :create - end - - directory "#{new_resource.name} :create #{include_dir}" do - path include_dir - owner new_resource.owner - group new_resource.group - mode '0750' - recursive true - action :create - end - - template "#{new_resource.name} :create #{include_dir}/#{new_resource.config_name}.cnf" do - path "#{include_dir}/#{new_resource.config_name}.cnf" - owner new_resource.owner - group new_resource.group - mode '0640' - variables(new_resource.variables) - source new_resource.source - cookbook new_resource.cookbook - action :create - end - end - - action :delete do - file "#{new_resource.name} :delete #{include_dir}/#{new_resource.config_name}.conf" do - path "#{include_dir}/#{new_resource.config_name}.conf" - action :delete - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_mysql_service_base.rb b/cookbooks/mysql/libraries/provider_mysql_service_base.rb deleted file mode 100644 index 5f19a45..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_service_base.rb +++ /dev/null @@ -1,250 +0,0 @@ -require 'chef/provider/lwrp_base' -require_relative 'helpers' - -class Chef - class Provider - class MysqlServiceBase < Chef::Provider::LWRPBase - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - # Mix in helpers from libraries/helpers.rb - include MysqlCookbook::Helpers - - # Service related methods referred to in the :create and :delete - # actions need to be implemented in the init system subclasses. - # - # create_stop_system_service - # delete_stop_service - - # All other methods are found in libraries/helpers.rb - # - # etc_dir, run_dir, log_dir, etc - - action :create do - # Yum, Apt, etc. From helpers.rb - configure_package_repositories - - # Software installation - package "#{new_resource.name} :create #{server_package_name}" do - package_name server_package_name - version parsed_version if node['platform'] == 'smartos' - version new_resource.package_version - action new_resource.package_action - end - - create_stop_system_service - - # Apparmor - configure_apparmor - - # System users - group "#{new_resource.name} :create mysql" do - group_name 'mysql' - action :create - end - - user "#{new_resource.name} :create mysql" do - username 'mysql' - gid 'mysql' - action :create - end - - # Yak shaving secion. Account for random errata. - # - # Turns out that mysqld is hard coded to try and read - # /etc/mysql/my.cnf, and its presence causes problems when - # setting up multiple services. - file "#{new_resource.name} :create #{prefix_dir}/etc/mysql/my.cnf" do - path "#{prefix_dir}/etc/mysql/my.cnf" - action :delete - end - - file "#{new_resource.name} :create #{prefix_dir}/etc/my.cnf" do - path "#{prefix_dir}/etc/my.cnf" - action :delete - end - - # mysql_install_db is broken on 5.6.13 - link "#{new_resource.name} :create #{prefix_dir}/usr/share/my-default.cnf" do - target_file "#{prefix_dir}/usr/share/my-default.cnf" - to "#{etc_dir}/my.cnf" - action :create - end - - # Support directories - directory "#{new_resource.name} :create #{etc_dir}" do - path etc_dir - owner new_resource.run_user - group new_resource.run_group - mode '0750' - recursive true - action :create - end - - directory "#{new_resource.name} :create #{include_dir}" do - path include_dir - owner new_resource.run_user - group new_resource.run_group - mode '0750' - recursive true - action :create - end - - directory "#{new_resource.name} :create #{run_dir}" do - path run_dir - owner new_resource.run_user - group new_resource.run_group - mode '0755' - recursive true - action :create - end - - directory "#{new_resource.name} :create #{log_dir}" do - path log_dir - owner new_resource.run_user - group new_resource.run_group - mode '0750' - recursive true - action :create - end - - directory "#{new_resource.name} :create #{parsed_data_dir}" do - path parsed_data_dir - owner new_resource.run_user - group new_resource.run_group - mode '0750' - recursive true - action :create - end - - # Main configuration file - template "#{new_resource.name} :create #{etc_dir}/my.cnf" do - path "#{etc_dir}/my.cnf" - source 'my.cnf.erb' - cookbook 'mysql' - owner new_resource.run_user - group new_resource.run_group - mode '0600' - variables( - config: new_resource, - error_log: error_log, - include_dir: include_dir, - lc_messages_dir: lc_messages_dir, - pid_file: pid_file, - socket_file: socket_file, - tmp_dir: tmp_dir, - data_dir: parsed_data_dir - ) - action :create - end - - # initialize database and create initial records - bash "#{new_resource.name} :create initial records" do - code init_records_script - returns [0, 1, 2] # facepalm - not_if "/usr/bin/test -f #{parsed_data_dir}/mysql/user.frm" - action :run - end - end - - action :delete do - # Stop the service before removing support directories - delete_stop_service - - directory "#{new_resource.name} :delete #{etc_dir}" do - path etc_dir - recursive true - action :delete - end - - directory "#{new_resource.name} :delete #{run_dir}" do - path run_dir - recursive true - action :delete - end - - directory "#{new_resource.name} :delete #{log_dir}" do - path log_dir - recursive true - action :delete - end - end - - # - # Platform specific bits - # - def configure_apparmor - # Do not add these resource if inside a container - # Only valid on Ubuntu - - unless ::File.exist?('/.dockerenv') || ::File.exist?('/.dockerinit') - if node['platform'] == 'ubuntu' - # Apparmor - package "#{new_resource.name} :create apparmor" do - package_name 'apparmor' - action :install - end - - directory "#{new_resource.name} :create /etc/apparmor.d/local/mysql" do - path '/etc/apparmor.d/local/mysql' - owner 'root' - group 'root' - mode '0755' - recursive true - action :create - end - - template "#{new_resource.name} :create /etc/apparmor.d/local/usr.sbin.mysqld" do - path '/etc/apparmor.d/local/usr.sbin.mysqld' - cookbook 'mysql' - source 'apparmor/usr.sbin.mysqld-local.erb' - owner 'root' - group 'root' - mode '0644' - action :create - notifies :restart, "service[#{new_resource.name} :create apparmor]", :immediately - end - - template "#{new_resource.name} :create /etc/apparmor.d/usr.sbin.mysqld" do - path '/etc/apparmor.d/usr.sbin.mysqld' - cookbook 'mysql' - source 'apparmor/usr.sbin.mysqld.erb' - owner 'root' - group 'root' - mode '0644' - action :create - notifies :restart, "service[#{new_resource.name} :create apparmor]", :immediately - end - - template "#{new_resource.name} :create /etc/apparmor.d/local/mysql/#{new_resource.instance}" do - path "/etc/apparmor.d/local/mysql/#{new_resource.instance}" - cookbook 'mysql' - source 'apparmor/usr.sbin.mysqld-instance.erb' - owner 'root' - group 'root' - mode '0644' - variables( - data_dir: parsed_data_dir, - mysql_name: mysql_name, - log_dir: log_dir, - run_dir: run_dir, - pid_file: pid_file, - socket_file: socket_file - ) - action :create - notifies :restart, "service[#{new_resource.name} :create apparmor]", :immediately - end - - service "#{new_resource.name} :create apparmor" do - service_name 'apparmor' - action :nothing - end - end - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_mysql_service_smf.rb b/cookbooks/mysql/libraries/provider_mysql_service_smf.rb deleted file mode 100644 index cc208c1..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_service_smf.rb +++ /dev/null @@ -1,91 +0,0 @@ -class Chef - class Provider - class MysqlServiceSmf < Chef::Provider::MysqlServiceBase - # FIXME: we should have a service_helper to determine if the platform supports SMF similarly - # to how we handle systemd on linux - if defined?(provides) # foodcritic ~FC023 - provides :mysql_service, os: %w(solaris2 omnios smartos openindiana opensolaris nexentacore) do - File.exist?('/usr/sbin/svccfg') - end - end - - action :start do - method_script_path = "/lib/svc/method/#{mysql_name}" if node['platform'] == 'omnios' - method_script_path = "/opt/local/lib/svc/method/#{mysql_name}" if node['platform'] == 'smartos' - - template "#{new_resource.name} :start #{method_script_path}" do - path method_script_path - cookbook 'mysql' - source 'smf/svc.method.mysqld.erb' - owner 'root' - group 'root' - mode '0555' - variables( - base_dir: base_dir, - data_dir: parsed_data_dir, - defaults_file: defaults_file, - error_log: error_log, - mysql_name: mysql_name, - mysqld_bin: mysqld_bin, - pid_file: pid_file - ) - action :create - end - - smf "#{new_resource.name} :start #{mysql_name}" do - name mysql_name - user new_resource.run_user - group new_resource.run_group - start_command "#{method_script_path} start" - end - - service "#{new_resource.name} :start #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Solaris - supports restart: true - action [:enable] - end - end - - action :stop do - service "#{new_resource.name} :stop #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Solaris - supports restart: true - action :stop - end - end - - action :restart do - service "#{new_resource.name} :restart #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Solaris - supports restart: true - action :restart - end - end - - action :reload do - service "#{new_resource.name} :reload #{mysql_name}" do - provider Chef::Provider::Service::Solaris - service_name mysql_name - supports reload: true - action :reload - end - end - - def create_stop_system_service - # nothing to do here - end - - def delete_stop_service - service "#{new_resource.name} :delete #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Solaris - supports restart: true - action :stop - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_mysql_service_systemd.rb b/cookbooks/mysql/libraries/provider_mysql_service_systemd.rb deleted file mode 100644 index 7ef415b..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_service_systemd.rb +++ /dev/null @@ -1,135 +0,0 @@ -require_relative 'provider_mysql_service_base' - -class Chef - class Provider - class MysqlServiceSystemd < Chef::Provider::MysqlServiceBase - if defined?(provides) # foodcritic ~FC023 - provides :mysql_service, os: 'linux' do - Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd) - end - end - - action :start do - # Needed for Debian / Ubuntu - directory '/usr/libexec' do - owner 'root' - group 'root' - mode '0755' - action :create - end - - # this script is called by the main systemd unit file, and - # spins around until the service is actually up and running. - template "#{new_resource.name} :start /usr/libexec/#{mysql_name}-wait-ready" do - path "/usr/libexec/#{mysql_name}-wait-ready" - source 'systemd/mysqld-wait-ready.erb' - owner 'root' - group 'root' - mode '0755' - variables(socket_file: socket_file) - cookbook 'mysql' - action :create - end - - # this is the main systemd unit file - template "#{new_resource.name} :start /lib/systemd/system/#{mysql_name}.service" do - path "/lib/systemd/system/#{mysql_name}.service" - source 'systemd/mysqld.service.erb' - owner 'root' - group 'root' - mode '0644' - variables( - config: new_resource, - etc_dir: etc_dir, - base_dir: base_dir, - mysqld_bin: mysqld_bin - ) - cookbook 'mysql' - notifies :run, "execute[#{new_resource.name} :start systemctl daemon-reload]", :immediately - action :create - end - - # avoid 'Unit file changed on disk' warning - execute "#{new_resource.name} :start systemctl daemon-reload" do - command '/bin/systemctl daemon-reload' - action :nothing - end - - # tmpfiles.d config so the service survives reboot - template "#{new_resource.name} :start /usr/lib/tmpfiles.d/#{mysql_name}.conf" do - path "/usr/lib/tmpfiles.d/#{mysql_name}.conf" - source 'tmpfiles.d.conf.erb' - owner 'root' - group 'root' - mode '0644' - variables( - run_dir: run_dir, - run_user: new_resource.run_user, - run_group: new_resource.run_group - ) - cookbook 'mysql' - action :create - end - - # service management resource - service "#{new_resource.name} :start #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Systemd - supports restart: true, status: true - action [:enable, :start] - end - end - - action :stop do - # service management resource - service "#{new_resource.name} :stop #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Systemd - supports status: true - action [:disable, :stop] - only_if { ::File.exist?("/usr/lib/systemd/system/#{mysql_name}.service") } - end - end - - action :restart do - # service management resource - service "#{new_resource.name} :restart #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Systemd - supports restart: true - action :restart - end - end - - action :reload do - # service management resource - service "#{new_resource.name} :reload #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Systemd - action :reload - end - end - - def create_stop_system_service - # service management resource - service "#{new_resource.name} :create mysql" do - service_name system_service_name - provider Chef::Provider::Service::Systemd - supports status: true - action [:stop, :disable] - end - end - - def delete_stop_service - # service management resource - service "#{new_resource.name} :delete #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Systemd - supports status: true - action [:disable, :stop] - only_if { ::File.exist?("/usr/lib/systemd/system/#{mysql_name}.service") } - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_mysql_service_sysvinit.rb b/cookbooks/mysql/libraries/provider_mysql_service_sysvinit.rb deleted file mode 100644 index b3f2259..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_service_sysvinit.rb +++ /dev/null @@ -1,89 +0,0 @@ -require_relative 'provider_mysql_service_base' - -class Chef - class Provider - class MysqlServiceSysvinit < Chef::Provider::MysqlServiceBase - provides :mysql_service, os: '!windows' if defined?(provides) - - action :start do - template "#{new_resource.name} :start /etc/init.d/#{mysql_name}" do - path "/etc/init.d/#{mysql_name}" - source 'sysvinit/mysqld.erb' - owner 'root' - group 'root' - mode '0755' - variables( - config: new_resource, - defaults_file: defaults_file, - error_log: error_log, - mysql_name: mysql_name, - mysqladmin_bin: mysqladmin_bin, - mysqld_safe_bin: mysqld_safe_bin, - pid_file: pid_file, - scl_name: scl_name - ) - cookbook 'mysql' - action :create - end - - service "#{new_resource.name} :start #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Init::Redhat if node['platform_family'] == 'redhat' - provider Chef::Provider::Service::Init::Insserv if node['platform_family'] == 'debian' - supports restart: true, status: true - action [:enable, :start] - end - end - - action :stop do - service "#{new_resource.name} :stop #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Init::Redhat if node['platform_family'] == 'redhat' - provider Chef::Provider::Service::Init::Insserv if node['platform_family'] == 'debian' - supports restart: true, status: true - action [:stop] - end - end - - action :restart do - service "#{new_resource.name} :restart #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Init::Redhat if node['platform_family'] == 'redhat' - provider Chef::Provider::Service::Init::Insserv if node['platform_family'] == 'debian' - supports restart: true - action :restart - end - end - - action :reload do - service "#{new_resource.name} :reload #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Init::Redhat if node['platform_family'] == 'redhat' - provider Chef::Provider::Service::Init::Insserv if node['platform_family'] == 'debian' - action :reload - end - end - - def create_stop_system_service - service "#{new_resource.name} :create #{system_service_name}" do - service_name system_service_name - provider Chef::Provider::Service::Init::Redhat if node['platform_family'] == 'redhat' - provider Chef::Provider::Service::Init::Insserv if node['platform_family'] == 'debian' - supports status: true - action [:stop, :disable] - end - end - - def delete_stop_service - service "#{new_resource.name} :delete #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Init::Redhat if node['platform_family'] == 'redhat' - provider Chef::Provider::Service::Init::Insserv if node['platform_family'] == 'debian' - supports status: true - action [:disable, :stop] - only_if { ::File.exist?("#{etc_dir}/init.d/#{mysql_name}") } - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_mysql_service_upstart.rb b/cookbooks/mysql/libraries/provider_mysql_service_upstart.rb deleted file mode 100644 index 3a328b6..0000000 --- a/cookbooks/mysql/libraries/provider_mysql_service_upstart.rb +++ /dev/null @@ -1,114 +0,0 @@ -require_relative 'provider_mysql_service_base' - -class Chef - class Provider - class MysqlServiceUpstart < Chef::Provider::MysqlServiceBase - if defined?(provides) # foodcritic ~FC023 - provides :mysql_service, os: 'linux' do - Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) && - !Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat) - end - end - - action :start do - template "#{new_resource.name} :start /usr/sbin/#{mysql_name}-wait-ready" do - path "/usr/sbin/#{mysql_name}-wait-ready" - source 'upstart/mysqld-wait-ready.erb' - owner 'root' - group 'root' - mode '0755' - variables(socket_file: socket_file) - cookbook 'mysql' - action :create - end - - template "#{new_resource.name} :start /etc/init/#{mysql_name}.conf" do - path "/etc/init/#{mysql_name}.conf" - source 'upstart/mysqld.erb' - owner 'root' - group 'root' - mode '0644' - variables( - defaults_file: defaults_file, - mysql_name: mysql_name, - run_group: new_resource.run_group, - run_user: new_resource.run_user, - socket_dir: socket_dir - ) - cookbook 'mysql' - action :create - end - - service "#{new_resource.name} :start #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - supports status: true - action [:start] - end - end - - action :stop do - service "#{new_resource.name} :stop #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - supports restart: true, status: true - action [:stop] - end - end - - action :restart do - # With Upstart, restarting the service doesn't behave "as expected". - # We want the post-start stanzas, which wait until the - # service is available before returning - # - # http://upstart.ubuntu.com/cookbook/#restart - service "#{new_resource.name} :restart stop #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - action :stop - end - - service "#{new_resource.name} :restart start #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - action :start - end - end - - action :reload do - # With Upstart, reload just sends a HUP signal to the process. - # As far as I can tell, this doesn't work the way it's - # supposed to, so we need to actually restart the service. - service "#{new_resource.name} :reload stop #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - action :stop - end - - service "#{new_resource.name} :reload start #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - action :start - end - end - - def create_stop_system_service - service "#{new_resource.name} :create #{system_service_name}" do - service_name system_service_name - provider Chef::Provider::Service::Upstart - supports status: true - action [:stop, :disable] - end - end - - def delete_stop_service - service "#{new_resource.name} :delete #{mysql_name}" do - service_name mysql_name - provider Chef::Provider::Service::Upstart - action [:disable, :stop] - only_if { ::File.exist?("#{etc_dir}/init/#{mysql_name}") } - end - end - end - end -end diff --git a/cookbooks/mysql/libraries/provider_priority_linux.rb b/cookbooks/mysql/libraries/provider_priority_linux.rb deleted file mode 100644 index cea5b11..0000000 --- a/cookbooks/mysql/libraries/provider_priority_linux.rb +++ /dev/null @@ -1,45 +0,0 @@ - -begin - require 'chef/platform/provider_priority_map' -rescue LoadError # rubocop: disable Lint/HandleExceptions -end - -require_relative 'provider_mysql_service_smf' -require_relative 'provider_mysql_service_systemd' -require_relative 'provider_mysql_service_sysvinit' -require_relative 'provider_mysql_service_upstart' -require_relative 'provider_mysql_config' -require_relative 'provider_mysql_client' - -if defined? Chef::Platform::ProviderPriorityMap - Chef::Platform::ProviderPriorityMap.instance.priority( - :mysql_service, - [Chef::Provider::MysqlServiceSystemd, Chef::Provider::MysqlServiceUpstart, Chef::Provider::MysqlServiceSysvinit], - os: 'linux' - ) -else - # provider mappings for Chef 11 - - # systemd service - Chef::Platform.set platform: :fedora, version: '>= 19', resource: :mysql_service, provider: Chef::Provider::MysqlServiceSystemd - Chef::Platform.set platform: :redhat, version: '>= 7.0', resource: :mysql_service, provider: Chef::Provider::MysqlServiceSystemd - Chef::Platform.set platform: :centos, version: '>= 7.0', resource: :mysql_service, provider: Chef::Provider::MysqlServiceSystemd - Chef::Platform.set platform: :scientific, version: '>= 7.0', resource: :mysql_service, provider: Chef::Provider::MysqlServiceSystemd - Chef::Platform.set platform: :oracle, version: '>= 7.0', resource: :mysql_service, provider: Chef::Provider::MysqlServiceSystemd - - # smf service - Chef::Platform.set platform: :omnios, resource: :mysql_service, provider: Chef::Provider::MysqlServiceSmf - Chef::Platform.set platform: :smartos, resource: :mysql_service, provider: Chef::Provider::MysqlServiceSmf - - # upstart service - Chef::Platform.set platform: :ubuntu, resource: :mysql_service, provider: Chef::Provider::MysqlServiceUpstart - - # default service - Chef::Platform.set resource: :mysql_service, provider: Chef::Provider::MysqlServiceSysvinit - - # config - Chef::Platform.set resource: :mysql_config, provider: Chef::Provider::MysqlConfig - - # client - Chef::Platform.set resource: :mysql_client, provider: Chef::Provider::MysqlClient -end diff --git a/cookbooks/mysql/libraries/resource_mysql_client.rb b/cookbooks/mysql/libraries/resource_mysql_client.rb deleted file mode 100644 index 8585dbe..0000000 --- a/cookbooks/mysql/libraries/resource_mysql_client.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'chef/resource/lwrp_base' - -class Chef - class Resource - class MysqlClient < Chef::Resource::LWRPBase - provides :mysql_client - - self.resource_name = :mysql_client - actions :create, :delete - default_action :create - - attribute :client_name, kind_of: String, name_attribute: true, required: true - attribute :package_name, kind_of: Array, default: nil - attribute :package_version, kind_of: String, default: nil - attribute :version, kind_of: String, default: nil # mysql_version - end - end -end diff --git a/cookbooks/mysql/libraries/resource_mysql_config.rb b/cookbooks/mysql/libraries/resource_mysql_config.rb deleted file mode 100644 index a8767ce..0000000 --- a/cookbooks/mysql/libraries/resource_mysql_config.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'chef/resource/lwrp_base' - -class Chef - class Resource - class MysqlConfig < Chef::Resource::LWRPBase - provides :mysql_config - - self.resource_name = :mysql_config - actions :create, :delete - default_action :create - - attribute :config_name, kind_of: String, name_attribute: true, required: true - attribute :cookbook, kind_of: String, default: nil - attribute :group, kind_of: String, default: 'mysql' - attribute :instance, kind_of: String, default: 'default' - attribute :owner, kind_of: String, default: 'mysql' - attribute :source, kind_of: String, default: nil - attribute :variables, kind_of: [Hash], default: nil - attribute :version, kind_of: String, default: nil - end - end -end diff --git a/cookbooks/mysql/libraries/resource_mysql_service.rb b/cookbooks/mysql/libraries/resource_mysql_service.rb deleted file mode 100644 index 8d4f5d3..0000000 --- a/cookbooks/mysql/libraries/resource_mysql_service.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'chef/resource/lwrp_base' - -class Chef - class Resource - class MysqlService < Chef::Resource::LWRPBase - provides :mysql_service - - self.resource_name = :mysql_service - actions :create, :delete, :start, :stop, :restart, :reload - default_action :create - - attribute :charset, kind_of: String, default: 'utf8' - attribute :data_dir, kind_of: String, default: nil - attribute :initial_root_password, kind_of: String, default: 'ilikerandompasswords' - attribute :instance, kind_of: String, name_attribute: true - attribute :package_action, kind_of: Symbol, default: :install - attribute :package_name, kind_of: String, default: nil - attribute :package_version, kind_of: String, default: nil - attribute :bind_address, kind_of: String, default: nil - attribute :port, kind_of: [String, Integer], default: '3306' - attribute :run_group, kind_of: String, default: 'mysql' - attribute :run_user, kind_of: String, default: 'mysql' - attribute :socket, kind_of: String, default: nil - attribute :mysqld_options, kind_of: Hash, default: {} - attribute :version, kind_of: String, default: nil - attribute :error_log, kind_of: String, default: nil - attribute :tmp_dir, kind_of: String, default: nil - attribute :pid_file, kind_of: String, default: nil - end - end -end diff --git a/cookbooks/mysql/metadata.json b/cookbooks/mysql/metadata.json index 54c8e71..22bd441 100644 --- a/cookbooks/mysql/metadata.json +++ b/cookbooks/mysql/metadata.json @@ -1 +1 @@ -{"name":"mysql","version":"6.1.3","description":"Provides mysql_service, mysql_config, and mysql_client resources","long_description":"# MySQL Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/mysql.svg?branch=master)](https://travis-ci.org/chef-cookbooks/mysql) [![Cookbook Version](https://img.shields.io/cookbook/v/mysql.svg)](https://supermarket.chef.io/cookbooks/mysql)\n\nThe Mysql Cookbook is a library cookbook that provides resource primitives (LWRPs) for use in recipes. It is designed to be a reference example for creating highly reusable cross-platform cookbooks.\n\n## Scope\n\nThis cookbook is concerned with the \"MySQL Community Server\", particularly those shipped with F/OSS Unix and Linux distributions. It does not address forks or value-added repackaged MySQL distributions like Drizzle, MariaDB, or Percona.\n\n## Requirements\n\n- Chef 11 or higher\n- Ruby 1.9 or higher (preferably from the Chef full-stack installer)\n- Network accessible package repositories\n- 'recipe[selinux::disabled]' on RHEL platforms\n\n## Platform Support\n\nThe following platforms have been tested with Test Kitchen:\n\n```\n|----------------+-----+-----+-----+-----+-----|\n| | 5.0 | 5.1 | 5.5 | 5.6 | 5.7 |\n|----------------+-----+-----+-----+-----+-----|\n| debian-7 | | | X | | |\n|----------------+-----+-----+-----+-----+-----|\n| ubuntu-12.04 | | | X | | |\n|----------------+-----+-----+-----+-----+-----|\n| ubuntu-14.04 | | | X | X | |\n|----------------+-----+-----+-----+-----+-----|\n| ubuntu-15.04 | | | | X | |\n|----------------+-----+-----+-----+-----+-----|\n| centos-5 | X | X | X | X | X |\n|----------------+-----+-----+-----+-----+-----|\n| centos-6 | | X | X | X | X |\n|----------------+-----+-----+-----+-----+-----|\n| centos-7 | | | X | X | X |\n|----------------+-----+-----+-----+-----+-----|\n| amazon | | | X | X | X |\n|----------------+-----+-----+-----+-----+-----|\n| fedora-22 | | | X | X | X |\n|----------------+-----+-----+-----+-----+-----|\n| fedora-23 | | | X | X | X |\n|----------------+-----+-----+-----+-----+-----|\n```\n\n## Cookbook Dependencies\n\n- yum-mysql-community\n- smf\n\n## Usage\n\nPlace a dependency on the mysql cookbook in your cookbook's metadata.rb\n\n```ruby\ndepends 'mysql', '~> 6.0'\n```\n\nThen, in a recipe:\n\n```ruby\nmysql_service 'foo' do\n port '3306'\n version '5.5'\n initial_root_password 'change me'\n action [:create, :start]\nend\n```\n\nThe service name on the OS is `mysql-foo`. You can manually start and stop it with `service mysql-foo start` and `service mysql-foo stop`.\n\nThe configuration file is at `/etc/mysql-foo/my.cnf`. It contains the minimum options to get the service running. It looks like this.\n\n```\n# Chef generated my.cnf for instance mysql-foo\n\n[client]\ndefault-character-set = utf8\nport = 3306\nsocket = /var/run/mysql-foo/mysqld.sock\n\n[mysql]\ndefault-character-set = utf8\n\n[mysqld]\nuser = mysql\npid-file = /var/run/mysql-foo/mysqld.pid\nsocket = /var/run/mysql-foo/mysqld.sock\nport = 3306\ndatadir = /var/lib/mysql-foo\ntmpdir = /tmp\nlog-error = /var/log/mysql-foo/error.log\n!includedir /etc/mysql-foo/conf.d\n\n[mysqld_safe]\nsocket = /var/run/mysql-foo/mysqld.sock\n```\n\nYou can put extra configuration into the conf.d directory by using the `mysql_config` resource, like this:\n\n```ruby\nmysql_service 'foo' do\n port '3306'\n version '5.5'\n initial_root_password 'change me'\n action [:create, :start]\nend\n\nmysql_config 'foo' do\n source 'my_extra_settings.erb'\n notifies :restart, 'mysql_service[foo]'\n action :create\nend\n```\n\nYou are responsible for providing `my_extra_settings.erb` in your own cookbook's templates folder.\n\n## Connecting with the mysql CLI command\n\nLogging into the machine and typing `mysql` with no extra arguments will fail. You need to explicitly connect over the socket with `mysql -S /var/run/mysql-foo/mysqld.sock`, or over the network with `mysql -h 127.0.0.1`\n\n## Upgrading from older version of the mysql cookbook\n\n- It is strongly recommended that you rebuild the machine from scratch. This is easy if you have your `data_dir` on a dedicated mount point. If you _must_ upgrade in-place, follow the instructions below.\n- The 6.x series supports multiple service instances on a single machine. It dynamically names the support directories and service names. `/etc/mysql becomes /etc/mysql-instance_name`. Other support directories in `/var` `/run` etc work the same way. Make sure to specify the `data_dir` property on the `mysql_service` resource to point to the old `/var/lib/mysql` directory.\n\n## Resources Overview\n\n### mysql_service\n\nThe `mysql_service` resource manages the basic plumbing needed to get a MySQL server instance running with minimal configuration.\n\nThe `:create` action handles package installation, support directories, socket files, and other operating system level concerns. The internal configuration file contains just enough to get the service up and running, then loads extra configuration from a conf.d directory. Further configurations are managed with the `mysql_config` resource.\n\n- If the `data_dir` is empty, a database will be initialized, and a\n- root user will be set up with `initial_root_password`. If this\n- directory already contains database files, no action will be taken.\n\nThe `:start` action starts the service on the machine using the appropriate provider for the platform. The `:start` action should be omitted when used in recipes designed to build containers.\n\n#### Example\n\n```ruby\nmysql_service 'default' do\n version '5.7'\n bind_address '0.0.0.0'\n port '3306'\n data_dir '/data'\n initial_root_password 'Ch4ng3me'\n action [:create, :start]\nend\n```\n\nPlease note that when using `notifies` or `subscribes`, the resource to reference is `mysql_service[name]`, not `service[mysql]`.\n\n#### Parameters\n\n- `charset` - specifies the default character set. Defaults to `utf8`.\n- `data_dir` - determines where the actual data files are kept on the machine. This is useful when mounting external storage. When omitted, it will default to the platform's native location.\n- `error_log` - Tunable location of the error_log\n- `initial_root_password` - allows the user to specify the initial root password for mysql when initializing new databases. This can be set explicitly in a recipe, driven from a node attribute, or from data_bags. When omitted, it defaults to `ilikerandompasswords`. Please be sure to change it.\n- `instance` - A string to identify the MySQL service. By convention, to allow for multiple instances of the `mysql_service`, directories and files on disk are named `mysql-`. Defaults to the resource name.\n- `package_action` - Defaults to `:install`.\n- `package_name` - Defaults to a value looked up in an internal map.\n- `package_version` - Specific version of the package to install,passed onto the underlying package manager. Defaults to `nil`.\n- `bind_address` - determines the listen IP address for the mysqld service. When omitted, it will be determined by MySQL. If the address is \"regular\" IPv4/IPv6address (e.g 127.0.0.1 or ::1), the server accepts TCP/IP connections only for that particular address. If the address is \"0.0.0.0\" (IPv4) or \"::\" (IPv6), the server accepts TCP/IP connections on all IPv4 or IPv6 interfaces.\n- `mysqld_options` - A key value hash of options to be rendered into the main my.cnf. WARNING - It is highly recommended that you use the `mysql_config` resource instead of sending extra config into a `mysql_service` resource. This will allow you to set up notifications and subscriptions between the service and its configuration. That being said, this can be useful for adding extra options needed for database initialization at first run.\n- `port` - determines the listen port for the mysqld service. When omitted, it will default to '3306'.\n- `run_group` - The name of the system group the `mysql_service` should run as. Defaults to 'mysql'.\n- `run_user` - The name of the system user the `mysql_service` should run as. Defaults to 'mysql'.\n- `pid_file` - Tunable location of the pid file.\n- `socket` - determines where to write the socket file for the `mysql_service` instance. Useful when configuring clients on the same machine to talk over socket and skip the networking stack. Defaults to a calculated value based on platform and instance name.\n- `tmp_dir` - Tunable location of the tmp_dir\n- `version` - allows the user to select from the versions available for the platform, where applicable. When omitted, it will install the default MySQL version for the target platform. Available version numbers are `5.0`, `5.1`, `5.5`, `5.6`, and `5.7`, depending on platform.\n\n#### Actions\n\n- `:create` - Configures everything but the underlying operating system service.\n- `:delete` - Removes everything but the package and data_dir.\n- `:start` - Starts the underlying operating system service\n- `:stop`- Stops the underlying operating system service\n- `:restart` - Restarts the underlying operating system service\n- `:reload` - Reloads the underlying operating system service\n\n#### Providers\n\nChef selects the appropriate provider based on platform and version, but you can specify one if your platform support it.\n\n```ruby\nmysql_service[instance-1] do\n port '1234'\n data_dir '/mnt/lottadisk'\n provider Chef::Provider::MysqlServiceSysvinit\n action [:create, :start]\nend\n```\n\n- `Chef::Provider::MysqlServiceBase` - Configures everything needed to run a MySQL service except the platform service facility. This provider should never be used directly. The `:start`, `:stop`, `:restart`, and `:reload` actions are stubs meant to be overridden by the providers below.\n- `Chef::Provider::MysqlServiceSmf` - Starts a `mysql_service` using the Service Management Facility, used by Solaris and Illumos. Manages the FMRI and method script.\n- `Chef::Provider::MysqlServiceSystemd` - Starts a `mysql_service` using SystemD. Manages the unit file and activation state\n- `Chef::Provider::MysqlServiceSysvinit` - Starts a `mysql_service` using SysVinit. Manages the init script and status.\n- `Chef::Provider::MysqlServiceUpstart` - Starts a `mysql_service` using Upstart. Manages job definitions and status.\n\n### mysql_config\n\nThe `mysql_config` resource is a wrapper around the core Chef `template` resource. Instead of a `path` parameter, it uses the `instance` parameter to calculate the path on the filesystem where file is rendered.\n\n#### Example\n\n```ruby\nmysql_config[default] do\n source 'site.cnf.erb'\n action :create\nend\n```\n\n#### Parameters\n\n- `config_name` - The base name of the configuration file to be rendered into the conf.d directory on disk. Defaults to the resource name.\n- `cookbook` - The name of the cookbook to look for the template source. Defaults to nil\n- `group` - System group for file ownership. Defaults to 'mysql'.\n- `instance` - Name of the `mysql_service` instance the config is meant for. Defaults to 'default'.\n- `owner` - System user for file ownership. Defaults to 'mysql'.\n- `source` - Template in cookbook to be rendered.\n- `variables` - Variables to be passed to the underlying `template` resource.\n- `version` - Version of the `mysql_service` instance the config is meant for. Used to calculate path. Only necessary when using packages with unique configuration paths, such as RHEL Software Collections or OmniOS. Defaults to 'nil'\n\n#### Actions\n\n- `:create` - Renders the template to disk at a path calculated using the instance parameter.\n- `:delete` - Deletes the file from the conf.d directory calculated using the instance parameter.\n\n#### More Examples\n\n```ruby\nmysql_service 'instance-1' do\n action [:create, :start]\nend\n\nmysql_service 'instance-2' do\n action [:create, :start]\nend\n\nmysql_config 'logging' do\n instance 'instance-1'\n source 'logging.cnf.erb'\n action :create\n notifies :restart, 'mysql_service[instance-1]'\nend\n\nmysql_config 'security settings for instance-2' do\n config_name 'security'\n instance 'instance-2'\n source 'security_stuff.cnf.erb'\n variables(:foo => 'bar')\n action :create\n notifies :restart, 'mysql_service[instance-2]'\nend\n```\n\n### mysql_client\n\nThe `mysql_client` resource manages the MySQL client binaries and development libraries.\n\nIt is an example of a \"singleton\" resource. Declaring two `mysql_client` resources on a machine usually won't yield two separate copies of the client binaries, except for platforms that support multiple versions (RHEL SCL, OmniOS).\n\n#### Example\n\n```ruby\nmysql_client 'default' do\n action :create\nend\n```\n\n#### Parameters\n\n- `package_name` - An array of packages to be installed. Defaults to a value looked up in an internal map.\n- `package_version` - Specific versions of the package to install, passed onto the underlying package manager. Defaults to `nil`.\n- `version` - Major MySQL version number of client packages. Only valid on for platforms that support multiple versions, such as RHEL via Software Collections and OmniOS.\n\n#### Actions\n\n- `:create` - Installs the client software\n- `:delete` - Removes the client software\n\n## Advanced Usage Examples\n\nThere are a number of configuration scenarios supported by the use of resource primitives in recipes. For example, you might want to run multiple MySQL services, as different users, and mount block devices that contain pre-existing databases.\n\n### Multiple Instances as Different Users\n\n```ruby\n# instance-1\nuser 'alice' do\n action :create\nend\n\ndirectory '/mnt/data/mysql/instance-1' do\n owner 'alice'\n action :create\nend\n\nmount '/mnt/data/mysql/instance-1' do\n device '/dev/sdb1'\n fstype 'ext4'\n action [:mount, :enable]\nend\n\nmysql_service 'instance-1' do\n port '3307'\n run_user 'alice'\n data_dir '/mnt/data/mysql/instance-1'\n action [:create, :start]\nend\n\nmysql_config 'site config for instance-1' do\n instance 'instance-1'\n source 'instance-1.cnf.erb'\n notifies :restart, 'mysql_service[instance-1]'\nend\n\n# instance-2\nuser 'bob' do\n action :create\nend\n\ndirectory '/mnt/data/mysql/instance-2' do\n owner 'bob'\n action :create\nend\n\nmount '/mnt/data/mysql/instance-2' do\n device '/dev/sdc1'\n fstype 'ext3'\n action [:mount, :enable]\nend\n\nmysql_service 'instance-2' do\n port '3308'\n run_user 'bob'\n data_dir '/mnt/data/mysql/instance-2'\n action [:create, :start]\nend\n\nmysql_config 'site config for instance-2' do\n instance 'instance-2'\n source 'instance-2.cnf.erb'\n notifies :restart, 'mysql_service[instance-2]'\nend\n```\n\n### Replication Testing\n\nUse multiple `mysql_service` instances to test a replication setup. This particular example serves as a smoke test in Test Kitchen because it exercises different resources and requires service restarts.\n\n\n\n## Frequently Asked Questions\n\n### How do I run this behind my firewall?\n\nOn Linux, the `mysql_service` resource uses the platform's underlying package manager to install software. For this to work behind firewalls, you'll need to either:\n\n- Configure the system yum/apt utilities to use a proxy server that\n- can reach the Internet\n- Host a package repository on a network that the machine can talk to\n\nOn the RHEL platform_family, applying the `yum::default` recipe will allow you to drive the `yum_globalconfig` resource with attributes to change the global yum proxy settings.\n\nIf hosting repository mirrors, applying one of the following recipes and adjust the settings with node attributes.\n\n- `recipe[yum-centos::default]` from the Supermarket\n\n \n\n \n\n- `recipe[yum-mysql-community::default]` from the Supermarket\n\n \n\n \n\n### The mysql command line doesn't work\n\nIf you log into the machine and type `mysql`, you may see an error like this one:\n\n`Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'`\n\nThis is because MySQL is hardcoded to read the defined default my.cnf file, typically at /etc/my.cnf, and this LWRP deletes it to prevent overlap among multiple MySQL configurations.\n\nTo connect to the socket from the command line, check the socket in the relevant my.cnf file and use something like this:\n\n`mysql -S /var/run/mysql-foo/mysqld.sock -Pwhatever`\n\nOr to connect over the network, use something like this: connect over the network..\n\n`mysql -h 127.0.0.1 -Pwhatever`\n\nThese network or socket ssettings can also be put in you $HOME/.my.cnf, if preferred.\n\n### What about MariaDB, Percona, Drizzle, WebScaleSQL, etc.\n\nMySQL forks are purposefully out of scope for this cookbook. This is mostly to reduce the testing matrix to a manageable size. Cookbooks for these technologies can easily be created by copying and adapting this cookbook. However, there will be differences.\n\nPackage repository locations, package version names, software major version numbers, supported platform matrices, and the availability of software such as XtraDB and Galera are the main reasons that creating multiple cookbooks to make sense.\n\n## Warnings\n\n## Hacking / Testing / TODO\n\nPlease refer to the HACKING.md\n\n## License & Authors\n\n- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))\n- Author:: AJ Christensen ([aj@chef.io](mailto:aj@chef.io))\n- Author:: Seth Chisamore ([schisamo@chef.io](mailto:schisamo@chef.io))\n- Author:: Brian Bianco ([brian.bianco@gmail.com](mailto:brian.bianco@gmail.com))\n- Author:: Jesse Howarth ([him@jessehowarth.com](mailto:him@jessehowarth.com))\n- Author:: Andrew Crump ([andrew@kotirisoftware.com](mailto:andrew@kotirisoftware.com))\n- Author:: Christoph Hartmann ([chris@lollyrock.com](mailto:chris@lollyrock.com))\n- Author:: Sean OMeara ([sean@chef.io](mailto:sean@chef.io))\n\n```text\nCopyright:: 2009-2014 Chef Software, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","scientific":">= 0.0.0","fedora":">= 0.0.0","debian":">= 0.0.0","ubuntu":">= 0.0.0","smartos":">= 0.0.0","omnios":">= 0.0.0","suse":">= 0.0.0"},"dependencies":{"yum-mysql-community":">= 0.0.0","smf":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file +{"name":"mysql","version":"8.4.0","description":"Provides mysql_service, mysql_config, and mysql_client resources","long_description":"","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"redhat":">= 6.0","centos":">= 6.0","scientific":">= 6.0","oracle":">= 6.0","amazon":">= 0.0.0","fedora":">= 0.0.0","debian":">= 7.0","ubuntu":">= 12.04","opensuse":">= 13.0","opensuseleap":">= 0.0.0","suse":">= 12.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/chef-cookbooks/mysql","issues_url":"https://github.com/chef-cookbooks/mysql/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld-instance.erb b/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld-instance.erb index 430a311..130beb7 100644 --- a/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld-instance.erb +++ b/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld-instance.erb @@ -2,12 +2,13 @@ /etc/<%= @mysql_name %>/conf.d/ r, /etc/<%= @mysql_name %>/conf.d/* r, /etc/<%= @mysql_name %>/my.cnf r, -<%= @log_dir %>/ r, -<%= @log_dir %>/* rw, -<%= @data_dir %>/ r, -<%= @data_dir %>/** rwk, -<%= @run_dir %>/** rw, -<%= @pid_file %> rw, -<%= @socket_file %> rw, +<%= @config.log_dir %>/ r, +<%= @config.log_dir %>/* rw, +<%= @config.data_dir %>/ r, +<%= @config.data_dir %>/** rwk, +<%= @config.run_dir %>/** rw, +<%= @config.pid_file %> rw, +<%= @config.socket_file %> rw, /tmp/<%= @mysql_name %>/ r, /tmp/<%= @mysql_name %>/my.sql r, +<%= @config.tmp_dir %>/* rw, diff --git a/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld.erb b/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld.erb index 3e1f1b0..19ddbf5 100644 --- a/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld.erb +++ b/cookbooks/mysql/templates/default/apparmor/usr.sbin.mysqld.erb @@ -35,8 +35,10 @@ /var/log/mysql/* rw, /var/run/mysqld/mysqld.pid rw, /var/run/mysqld/mysqld.sock w, + /var/run/mysqld/mysqld.sock.lock rw, /run/mysqld/mysqld.pid rw, /run/mysqld/mysqld.sock w, + /run/mysqld/mysqld.sock.lock rw, /sys/devices/system/cpu/ r, diff --git a/cookbooks/mysql/templates/default/my.cnf.erb b/cookbooks/mysql/templates/default/my.cnf.erb index faa8d3e..ff10156 100644 --- a/cookbooks/mysql/templates/default/my.cnf.erb +++ b/cookbooks/mysql/templates/default/my.cnf.erb @@ -7,8 +7,8 @@ default-character-set = <%= @config.charset %> <% if @config.port %> port = <%= @config.port %> <% end %> -<% if @socket_file %> -socket = <%= @socket_file %> +<% if @config.socket_file %> +socket = <%= @config.socket_file %> <% end %> [mysql] @@ -20,11 +20,11 @@ default-character-set = <%= @config.charset %> <% if @config.run_user %> user = <%= @config.run_user %> <% end %> -<% if @pid_file %> -pid-file = <%= @pid_file %> +<% if @config.pid_file %> +pid-file = <%= @config.pid_file %> <% end %> -<% if @socket_file %> -socket = <%= @socket_file %> +<% if @config.socket_file %> +socket = <%= @config.socket_file %> <% end %> <% if @config.bind_address %> bind-address = <%= @config.bind_address %> @@ -32,26 +32,26 @@ bind-address = <%= @config.bind_address %> <% if @config.port %> port = <%= @config.port %> <% end %> -<% if @data_dir %> -datadir = <%= @data_dir %> +<% if @config.data_dir %> +datadir = <%= @config.data_dir %> <% end %> -<% if @tmp_dir %> -tmpdir = <%= @tmp_dir %> +<% if @config.tmp_dir %> +tmpdir = <%= @config.tmp_dir %> <% end %> <% @config.mysqld_options.each do |option,value| %> <%= option %> = <%= value %> <% end %> -<% if @lc_messages_dir %> -lc-messages-dir = <%= @lc_messages_dir %> +<% if @config.lc_messages_dir %> +lc-messages-dir = <%= @config.lc_messages_dir %> <% end %> -<% if @error_log %> -log-error = <%= @error_log %> +<% if @config.error_log %> +log-error = <%= @config.error_log %> <% end %> -<% if @include_dir %> -!includedir <%= @include_dir %> +<% if @config.include_dir %> +!includedir <%= @config.include_dir %> <% end %> [mysqld_safe] -<% if @socket_file %> -socket = <%= @socket_file %> +<% if @config.socket_file %> +socket = <%= @config.socket_file %> <% end %> diff --git a/cookbooks/chef_client_updater/.foodcritic b/cookbooks/mysql2_chef_gem/.foodcritic similarity index 100% rename from cookbooks/chef_client_updater/.foodcritic rename to cookbooks/mysql2_chef_gem/.foodcritic diff --git a/cookbooks/mysql2_chef_gem/CHANGELOG.md b/cookbooks/mysql2_chef_gem/CHANGELOG.md index f41303c..aa192b0 100644 --- a/cookbooks/mysql2_chef_gem/CHANGELOG.md +++ b/cookbooks/mysql2_chef_gem/CHANGELOG.md @@ -1,30 +1,56 @@ -mysql2_chef_gem CHANGELOG -======================== +# mysql2_chef_gem CHANGELOG + +## 2.0.1 (2017-03-28) + +- Include usage examples for installing on a mariadb server and included a note in the readme regarding the 2.0 changes. + +## 2.0.0 (2017-03-28) + +- Converted the previously HWRP resources/providers to a custom resource. This changes the behavior of choosing to install on mysql or mariadb in a breaking way. Instead of specifying the providers you need to call the resources directly. Specifying mysql2_chef_gem will default to mysql, but using mariadb will require using the mysql2_chef_gem_mariadb resource directly. +- Increase the minimum chef version to 12.5 +- Require mysql cookbook 8.2+ and build-essential cookbook 2.4+ +- Install the 0.4.5 gem by default +- Expand test recipe to cover more scenarios +- Switched testing to use Delivery local mode +- Switched from kitchen-docker to kitchen-dokken and removed testing for CentOS 5 / Ubuntu 12.04 as these are both going EOL +- Switched from Rubocop to cookstyle for linting +- Removed yum/apt from the Berksfile +- Remove test dependencies from the Gemfile and instead use ChefDK for testing + +## 1.1.0 (2016-04-27) + +- Added a chefignore file +- Loosen the dependency on mysql cookbook to allow for the use of the latest version +- Added source_url and issue_url metadata +- Added long_description metadata +- Removed the AWS based Test Kitchen testing and replaced with with kitchen-docker in Travis +- Updated Chefspec format to remove deprecation warnings +- Added Oracle Linux to the metadata + +## 1.0.2 (2015-06-29) -1.0.2 (2015-06-29) ------------------- - Updating metadata to depend on mysql ~> 6.0 -1.0.1 (2014-12-25) ------------------- +## 1.0.1 (2014-12-25) + - Moving from recipe_eval in to include_recipe LWRP -1.0.0 (2014-12-23) ------------------- +## 1.0.0 (2014-12-23) + - Replacing recipes with resources - Mysql and MariaDB providers for linking mysql2 gem - Expanded platform test coverage -0.1.1 (2014-09-15) ------------------- +## 0.1.1 (2014-09-15) + - Correct a typo in documentation - Correct a test failing with Travis CI -0.1.0 (2014-09-15) ------------------- +## 0.1.0 (2014-09-15) + - Correct documentation - Correct rubocop offenses -0.0.3 (2014-09-12) ------------------- +## 0.0.3 (2014-09-12) + - Initial release (copy of mysql-chef_gem, but for mysql2) diff --git a/cookbooks/mysql2_chef_gem/README.md b/cookbooks/mysql2_chef_gem/README.md index 97c4f68..e294bba 100644 --- a/cookbooks/mysql2_chef_gem/README.md +++ b/cookbooks/mysql2_chef_gem/README.md @@ -1,29 +1,20 @@ -Mysql2 Chef Gem Installer Cookbook -================================== +# Mysql2 Chef Gem Installer Cookbook -[![Build Status](https://travis-ci.org/sinfomicien/mysql2_chef_gem.png)](https://travis-ci.org/sinfomicien/mysql2_chef_gem) +[![Build Status](https://travis-ci.org/sinfomicien/mysql2_chef_gem.svg)](https://travis-ci.org/sinfomicien/mysql2_chef_gem) [![Cookbook Version](http://img.shields.io/cookbook/v/mysql2_chef_gem.svg)](https://supermarket.chef.io/cookbooks/mysql2_chef_gem) -mysql2_chef_gem is a library cookbook that provides an LWRP for use -in recipes. It provides a wrapper around `chef_gem` called -`mysql2_chef_gem` that eases the installation process, collecting the -prerequisites and side-stepping the compilation phase arms race. +mysql2_chef_gem is a library cookbook that provides a resource for installing the mysql2 gem against either mysql or mariadb depending on usage. -Scope ------ -This cookbook is concerned with the installation of the `mysql2` -Rubygem into Chef's gem path. Installation into other Ruby -environments, or installation of related gems such as `mysql` are -outside the scope of this cookbook. +## Scope -Requirements ------------- -* Chef 11 or higher -* Ruby 1.9 (preferably from the Chef full-stack installer) +This cookbook is concerned with the installation of the `mysql2` Rubygem into Chef's gem path. Installation into other Ruby environments, or installation of related gems such as `mysql` are outside the scope of this cookbook. -Platform Support ----------------- -The following platforms have been tested with Test Kitchen and are -known to work. +## Requirements + +- Chef 12.5+ + +## Platform Support + +The following platforms have been tested with Test Kitchen and are known to work. ``` |---------------------------------------+-----+-----+-----+-----+-----| @@ -35,27 +26,24 @@ known to work. |---------------------------------------+-----+-----+-----+-----+-----| | Mysql2ChefGem::Mysql / centos-7 | | | X | X | X | |---------------------------------------+-----+-----+-----+-----+-----| -| Mysql2ChefGem::Mysql / fedora-20 | | | X | X | X | +| Mysql2ChefGem::Mysql / fedora | | | X | X | X | |---------------------------------------+-----+-----+-----+-----+-----| | Mysql2ChefGem::Mysql / debian-7 | | | X | | | |---------------------------------------+-----+-----+-----+-----+-----| -| Mysql2ChefGem::Mysql / ubuntu-10.04 | | X | | | | -|---------------------------------------+-----+-----+-----+-----+-----| -| Mysql2ChefGem::Mysql / ubuntu-12.04 | | | X | | | -|---------------------------------------+-----+-----+-----+-----+-----| | Mysql2ChefGem::Mysql / ubuntu-14.04 | | | X | X | | |---------------------------------------+-----+-----+-----+-----+-----| -| Mysql2ChefGem::Mariadb / fedora-20 | | | X | | | +| Mysql2ChefGem::Mariadb / fedora | | | X | | | |---------------------------------------+-----+-----+-----+-----+-----| | Mysql2ChefGem::Mariadb / ubuntu-14.04 | | | X | | | |---------------------------------------+-----+-----+-----+-----+-----| ``` -Usage ------ +## Usage + Place a dependency on the mysql cookbook in your cookbook's metadata.rb + ```ruby -depends 'mysql2_chef_gem', '~> 1.0' +depends 'mysql2_chef_gem' ``` Then, in a recipe: @@ -66,43 +54,61 @@ mysql2_chef_gem 'default' do end ``` -Resources Overview ------------------- +### 2.0 Compatibility + +In order to ensure compatibility with Chef 13, the 2.0 release of this cookbook changed the method used to specify installation against mariadb. Instead of specifying the underlying provider, you instead reference the mariadb specific resource. See the example below for the new syntax. + +## Resources Overview + ### mysql2_chef_gem -The `mysql2_chef_gem` resource the build dependencies and installation -of the `mysql2` rubygem into Chef's Ruby environment +The `mysql2_chef_gem` resource installs mysql client development dependencies and installs the `mysql2` rubygem into Chef's Ruby environment. #### Example + ```ruby mysql2_chef_gem 'default' do - gem_version '0.3.17' + gem_version '0.4.5' action :install end ``` -#### Parameters -- `gem_version` - The version of the `mysql` Rubygem to install into - the Chef environment. Defaults to '0.3.17' - connector libraries -- `client_version` - The version of the mysql client libraries to - install and link against + +#### Properties + +- `gem_version` - The version of the `mysql` Rubygem to install into the Chef environment. Defaults to '0.4.5' connector libraries +- `package_version` - The version of the mysql client libraries to install and link against #### Actions + - `:install` - Build and install the gem into the Chef environment - `:remove` - Delete the gem from the Chef environment -#### Providers -Chef selects a default provider based on platform and version, -but you can specify one if your platform support it. +### mysql2_chef_gem_mariadb + +To install the mysql2 gem against an installation of mariadb reference the `mysql2_chef_gem_mariadb` resource directly. This resource includes all the same properties of the standard `mysql2_chef_gem` resource. ```ruby -mysql2_chef_gem 'default' do - provider Chef::Provider::Mysql2ChefGem::Mariadb +mysql2_chef_gem_mariadb 'default' do action :install end ``` -Authors -------- -- Author:: Sean OMeara () -- Author:: Nicolas Blanc() +## License & Authors + +- Author:: Sean OMeara ([someara@sean.io](mailto:someara@sean.io)) +- Author:: Tim Smith ([tsmith@chef.io](mailto:tsmith@chef.io)) +- Author:: Nicolas Blanc([sinfomicien@gmail.com](mailto:sinfomicien@gmail.com)) + +``` +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/cookbooks/mysql2_chef_gem/libraries/provider_mysql2_chef_gem_mariadb.rb b/cookbooks/mysql2_chef_gem/libraries/provider_mysql2_chef_gem_mariadb.rb deleted file mode 100644 index e25a427..0000000 --- a/cookbooks/mysql2_chef_gem/libraries/provider_mysql2_chef_gem_mariadb.rb +++ /dev/null @@ -1,37 +0,0 @@ -class Chef - class Provider - class Mysql2ChefGem - class Mariadb < Chef::Provider::LWRPBase - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - action :install do - recipe_eval do - run_context.include_recipe 'build-essential::default' - end - - # As a recipe: must rely on global node attributes - recipe_eval do - run_context.include_recipe 'mariadb::client' - end - - gem_package 'mysql2' do - gem_binary RbConfig::CONFIG['bindir'] + '/gem' - version new_resource.gem_version - action :install - end - end - - action :remove do - gem_package 'mysql2' do - gem_binary RbConfig::CONFIG['bindir'] + '/gem' - action :remove - end - end - end - end - end -end diff --git a/cookbooks/mysql2_chef_gem/libraries/provider_mysql2_chef_gem_mysql.rb b/cookbooks/mysql2_chef_gem/libraries/provider_mysql2_chef_gem_mysql.rb deleted file mode 100644 index cc1bace..0000000 --- a/cookbooks/mysql2_chef_gem/libraries/provider_mysql2_chef_gem_mysql.rb +++ /dev/null @@ -1,37 +0,0 @@ -class Chef - class Provider - class Mysql2ChefGem - class Mysql < Chef::Provider::LWRPBase - include Chef::DSL::IncludeRecipe - use_inline_resources if defined?(use_inline_resources) - - def whyrun_supported? - true - end - - action :install do - include_recipe 'build-essential::default' - - # As a resource: can pass version from calling recipe - mysql_client 'default' do - version new_resource.client_version - action :create - end - - gem_package 'mysql2' do - gem_binary RbConfig::CONFIG['bindir'] + '/gem' - version new_resource.gem_version - action :install - end - end - - action :remove do - gem_package 'mysql2' do - gem_binary RbConfig::CONFIG['bindir'] + '/gem' - action :remove - end - end - end - end - end -end diff --git a/cookbooks/mysql2_chef_gem/libraries/resource_mysql2_chef_gem.rb b/cookbooks/mysql2_chef_gem/libraries/resource_mysql2_chef_gem.rb deleted file mode 100644 index 92ba02f..0000000 --- a/cookbooks/mysql2_chef_gem/libraries/resource_mysql2_chef_gem.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'chef/resource/lwrp_base' - -class Chef - class Resource - class Mysql2ChefGem < Chef::Resource::LWRPBase - self.resource_name = :mysql2_chef_gem - actions :install, :remove - default_action :install - - attribute :mysql2_chef_gem_name, kind_of: String, name_attribute: true, required: true - attribute :gem_version, kind_of: String, default: '0.3.17' - attribute :client_version, kind_of: String, default: nil - end - end -end diff --git a/cookbooks/mysql2_chef_gem/libraries/z_provider_mapping.rb b/cookbooks/mysql2_chef_gem/libraries/z_provider_mapping.rb deleted file mode 100644 index bf0d7aa..0000000 --- a/cookbooks/mysql2_chef_gem/libraries/z_provider_mapping.rb +++ /dev/null @@ -1,17 +0,0 @@ -######### -# mysql2_chef_gem -######### -Chef::Platform.set platform: :amazon, resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :centos, version: '< 7.0', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :centos, version: '>= 7.0', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :debian, resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :fedora, version: '< 19', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :fedora, version: '>= 19', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :omnios, resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :redhat, version: '< 7.0', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :redhat, version: '>= 7.0', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :scientific, version: '< 7.0', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :scientific, version: '>= 7.0', resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :smartos, resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :suse, resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql -Chef::Platform.set platform: :ubuntu, resource: :mysql2_chef_gem, provider: Chef::Provider::Mysql2ChefGem::Mysql diff --git a/cookbooks/mysql2_chef_gem/metadata.json b/cookbooks/mysql2_chef_gem/metadata.json index 5021c36..8144cd2 100644 --- a/cookbooks/mysql2_chef_gem/metadata.json +++ b/cookbooks/mysql2_chef_gem/metadata.json @@ -1 +1 @@ -{"name":"mysql2_chef_gem","version":"1.0.2","description":"Provides the mysql2_chef_gem resource","long_description":"","maintainer":"Nicolas Blanc","maintainer_email":"sinfomicien@gmail.com","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","scientific":">= 0.0.0","fedora":">= 0.0.0","debian":">= 0.0.0","ubuntu":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","mysql":"~> 6.0","mariadb":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file +{"name":"mysql2_chef_gem","version":"2.0.1","description":"Provides the mysql2_chef_gem resource","long_description":"# Mysql2 Chef Gem Installer Cookbook\n\n[![Build Status](https://travis-ci.org/sinfomicien/mysql2_chef_gem.svg)](https://travis-ci.org/sinfomicien/mysql2_chef_gem) [![Cookbook Version](http://img.shields.io/cookbook/v/mysql2_chef_gem.svg)](https://supermarket.chef.io/cookbooks/mysql2_chef_gem)\n\nmysql2_chef_gem is a library cookbook that provides a resource for installing the mysql2 gem against either mysql or mariadb depending on usage.\n\n## Scope\n\nThis cookbook is concerned with the installation of the `mysql2` Rubygem into Chef's gem path. Installation into other Ruby environments, or installation of related gems such as `mysql` are outside the scope of this cookbook.\n\n## Requirements\n\n- Chef 12.5+\n\n## Platform Support\n\nThe following platforms have been tested with Test Kitchen and are known to work.\n\n```\n|---------------------------------------+-----+-----+-----+-----+-----|\n| | 5.0 | 5.1 | 5.5 | 5.6 | 5.7 |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mysql / centos-5 | X | | | X | X |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mysql / centos-6 | | X | X | X | X |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mysql / centos-7 | | | X | X | X |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mysql / fedora | | | X | X | X |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mysql / debian-7 | | | X | | |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mysql / ubuntu-14.04 | | | X | X | |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mariadb / fedora | | | X | | |\n|---------------------------------------+-----+-----+-----+-----+-----|\n| Mysql2ChefGem::Mariadb / ubuntu-14.04 | | | X | | |\n|---------------------------------------+-----+-----+-----+-----+-----|\n```\n\n## Usage\n\nPlace a dependency on the mysql cookbook in your cookbook's metadata.rb\n\n```ruby\ndepends 'mysql2_chef_gem'\n```\n\nThen, in a recipe:\n\n```ruby\nmysql2_chef_gem 'default' do\n action :install\nend\n```\n\n### 2.0 Compatibility\n\nIn order to ensure compatibility with Chef 13, the 2.0 release of this cookbook changed the method used to specify installation against mariadb. Instead of specifying the underlying provider, you instead reference the mariadb specific resource. See the example below for the new syntax.\n\n## Resources Overview\n\n### mysql2_chef_gem\n\nThe `mysql2_chef_gem` resource installs mysql client development dependencies and installs the `mysql2` rubygem into Chef's Ruby environment.\n\n#### Example\n\n```ruby\nmysql2_chef_gem 'default' do\n gem_version '0.4.5'\n action :install\nend\n```\n\n#### Properties\n\n- `gem_version` - The version of the `mysql` Rubygem to install into the Chef environment. Defaults to '0.4.5' connector libraries\n- `package_version` - The version of the mysql client libraries to install and link against\n\n#### Actions\n\n- `:install` - Build and install the gem into the Chef environment\n- `:remove` - Delete the gem from the Chef environment\n\n### mysql2_chef_gem_mariadb\n\nTo install the mysql2 gem against an installation of mariadb reference the `mysql2_chef_gem_mariadb` resource directly. This resource includes all the same properties of the standard `mysql2_chef_gem` resource.\n\n```ruby\nmysql2_chef_gem_mariadb 'default' do\n action :install\nend\n```\n\n## License & Authors\n\n- Author:: Sean OMeara ([someara@sean.io](mailto:someara@sean.io))\n- Author:: Tim Smith ([tsmith@chef.io](mailto:tsmith@chef.io))\n- Author:: Nicolas Blanc([sinfomicien@gmail.com](mailto:sinfomicien@gmail.com))\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Nicolas Blanc","maintainer_email":"sinfomicien@gmail.com","license":"Apache 2.0","platforms":{"centos":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0","fedora":">= 0.0.0","debian":">= 0.0.0","ubuntu":">= 0.0.0"},"dependencies":{"build-essential":">= 2.4.0","mysql":">= 8.2.0","mariadb":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{},"source_url":"https://github.com/sinfomicien/mysql2_chef_gem","issues_url":"https://github.com/sinfomicien/mysql2_chef_gem/issues","chef_version":">= 12.5","ohai_version":{}} \ No newline at end of file diff --git a/cookbooks/mysql2_chef_gem/resources/mysql2_chef_gem_mariadb.rb b/cookbooks/mysql2_chef_gem/resources/mysql2_chef_gem_mariadb.rb new file mode 100644 index 0000000..60ab5b2 --- /dev/null +++ b/cookbooks/mysql2_chef_gem/resources/mysql2_chef_gem_mariadb.rb @@ -0,0 +1,29 @@ +property :mysql2_chef_gem_name, String, name_attribute: true, required: true +property :gem_version, String, default: '0.4.5' +property :package_version, String + +provides :mysql2_chef_gem_mariadb + +action :install do + recipe_eval do + run_context.include_recipe 'build-essential::default' + end + + # As a recipe: must rely on global node attributes + recipe_eval do + run_context.include_recipe 'mariadb::client' + end + + gem_package 'mysql2' do + gem_binary RbConfig::CONFIG['bindir'] + '/gem' + version new_resource.gem_version + action :install + end +end + +action :remove do + gem_package 'mysql2' do + gem_binary RbConfig::CONFIG['bindir'] + '/gem' + action :remove + end +end diff --git a/cookbooks/mysql2_chef_gem/resources/mysql2_chef_gem_mysql.rb b/cookbooks/mysql2_chef_gem/resources/mysql2_chef_gem_mysql.rb new file mode 100644 index 0000000..28dd390 --- /dev/null +++ b/cookbooks/mysql2_chef_gem/resources/mysql2_chef_gem_mysql.rb @@ -0,0 +1,29 @@ +property :mysql2_chef_gem_name, String, name_attribute: true, required: true +property :gem_version, String, default: '0.4.5' +property :package_version, String + +provides :mysql2_chef_gem +provides :mysql2_chef_gem_mysql + +action :install do + include_recipe 'build-essential::default' + + # As a resource: can pass version from calling recipe + mysql_client 'default' do + version new_resource.package_version if new_resource.package_version + action :create + end + + gem_package 'mysql2' do + gem_binary RbConfig::CONFIG['bindir'] + '/gem' + version new_resource.gem_version + action :install + end +end + +action :remove do + gem_package 'mysql2' do + gem_binary RbConfig::CONFIG['bindir'] + '/gem' + action :remove + end +end diff --git a/cookbooks/ntp/CHANGELOG.md b/cookbooks/ntp/CHANGELOG.md new file mode 100644 index 0000000..290eb68 --- /dev/null +++ b/cookbooks/ntp/CHANGELOG.md @@ -0,0 +1,274 @@ +# ntp Cookbook CHANGELOG + +This file is used to list changes made in each version of the ntp cookbook. + +## 3.4.0 (2017-05-06) + +- Ensure metadata compatibility with older Chef 12 releases +- Testing updates for Chef 13 +- Test with Delivery local mode instead of a Rakefile +- Use a SPDX standard license string +- Remove xcp as a platform in the metadata +- Added requestkey attribute + +## 3.3.1 (2016-12-21) + +- Fix resource cloning warning in recipe[default] + +## 3.3.0 (2016-12-16) + +- Add Mac OS X client config support + +## 3.2.1 (2016-11-23) + +- Update leap seconds file to version 3676924800 + +## 3.2.0 (2016-09-28) + +- Remove support for Arch +- Remove legacy apparmor config that wasn't used +- Don't install ntpdate (and uninstall it) on Ubuntu 16.04+ +- Expand specs and avoid deprecation warnings + +## 3.1.0 (2016-09-16) + +- Require Chef 12.1 not 12.0 +- Remove the dependency on the Windows cookbook + +## 3.0.0 (2016-09-07) + +- Require Chef 12+ + +## 2.0.3 (2016-08-31) + +- Remove minitest tests from the undo recipe + +## 2.0.2 (2016-08-30) + +- Replace node.set with node.normal to avoid deprecation notices + +## 2.0.1 (2016-08-29) + +- Update the leap seconds file +- Remove node name from configs +- Switch to cookstyle and use the Rakefile directly for testing in Travis CI +- Update platforms we test on +- Fix failing Chefspecs and avoid deprecation warnings during spec runs + +## v2.0.0 (2016-05-18) + +- Remove the undo recipe. This functionality is better suited for a custom cookbook that matches the needs of individual organizations +- Removed the installation of the visual studio 2008 runtime that was only necessary for Windows 2003. +- Fixed the forced clock syncing on FreeBSD hosts + +## v1.11.1 (2016-05-12) + +- Ownership of this cookbook has been transferred back to Chef Software. + +## v1.11.0 (2016-03-29) + +- When force setting the clock run ntp as the ntp user to ensure we don't set file ownership to root +- Added optional support for orphan mode +- Require windows cookbook 1.38.0 to resolve several issues with the older cookbook versions +- Add support for using keys + +## v1.10.1 (2016-02-04) + +- Update the Readme to include openSUSE and Arch Linux +- Guard the timeout set in the service to prevent failures on old chef releases + +## v1.10.0 (2016-02-04) + +- Fixed compatibility with FreeBSD hosts by skipping the sync with the hardware clock and using the proper path to the "true" command +- Fixed compatibility with Windows by extending the service start timeout, introducing retries, and excluding Windows from the hardware sync logic +- Changed the default array of packages to install from ntp and ntpdate to just ntp. ntpdate is used on Debian and modern RHEL/Fedora hosts only. This gives us out of the box support for Arch and Suse +- Ensure that Fedora systems also install ntpdate +- Updated test dependencies to the latest +- Updated test documentation to point to the official Chef testing documentation +- Expanded the Test Kitchen config with better support for FreeBSD/Fedora and new Windows boxes + +## v1.9.2 (2016-02-04) + +- **PR [#121]** - Remove nomodify config from loopback + +## v1.9.1 (2016-01-07) + +- **PR [#132]** - Update ntp.leapseconds + +## v1.9.0 (2015-12-16) + +- **PR [#111]** - Fix duplication of localhost listen directive in template +- **PR [#127]** - Set `var_owner` on FreeBSD to root instead of default ntp +- **PR [#117]** - Document node['ntp']['ignore'] +- **PR [#118]** - Add attributes to support pld-linux +- **PR [#120]** - Fix links to Github PRs in the Changelog +- **PR [#124]** - Additional fix for apparmor issue gmiranda23#103 +- Depend on windows cookbook instead of suggesting. Suggests doesn't actually do anything +- Fix / expand apparmor specs to pass and test the auto apparmor config logic +- Enable Travis CI and update the travis.yml file to run full integration tests with Kitchen Docker so we test all PRs on Ubuntu 12.04/14.04 and CentOS 6.7 / 7.1 +- Reformat all markdown files +- Update all references to Opscode to be Chef Software. +- Update copyright dates and contact e-mails +- Expanded platforms in the Test Kitchen config +- Added new supermarket issues_url and source_url metadata +- Update the Berkfile API url and removed version pins on the testing cookbooks +- Remove yum from the Berksfile as it isn't actually used +- Use the standard Chef testing Rakefile +- Remove the attribute documentation from the metadata as it is quickly out of sync +- Resolve rubocop warnings and include the standard Chef rubocop.yml file +- Update development deps in the Gemfile to the latest releases +- Remove the outdated contributing.md doc from the Opscode days + +## v1.8.6 (2015-05-14) + +- **PR [#102](102)** - Update leapseconds file to 3660249600 (through C49) +- Gemfile parity with ChefDK 0.5.1 +- .kitchen.yml platform updates to current bento boxes + +## v1.8.4 (2015-04-17) + +- **PR [#101]** - add logfile attribute + +## v1.8.2 (2015-04-15) + +- **PR [#100]** - Sort peers & servers for consistency + +## v1.8.0 (2015-04-13) + +- Chefspec 4.0 updates +- Rubocop updates +- **PR [#85]** - Update leapseconds for June 2015 leapsecond +- **PR [#70]** - Allow setting tinker options in attributes +- **PR [#84]** - Add attributes for tinker option customization +- **PR [#88]** - Attribute sets noquery for localhost lines +- **PR [#89]** - ntp.leapseconds notifies ntp service with delayed restart +- **PR [#91]** - Allow ntp.conf update to restart immediate +- **PR [#95]** - Add preferred ntp server support +- **PR [#96]** - Add restrict default attribute +- **PR [#72]** - Move high stratum real CMOs to an attribute +- **PR [#98]** - Bump test-kitchen gem version +- **PR [#99]** - Lazy attribute for leapfile_enabled + +## v1.7.0 (2014-12-10) + +- Added CentOS 7 support for test-kitchen +- **PR [#37]** - Check that apparmor exists before enabling service +- **PR [#45]** - Statistics logging switch (not available for Windows) +- **PR [#57]** - Move include statement on helper outside 'windows?' check +- **PR [#71]** - Ability to listen more than one interface +- **PR [#73]** - Fix appamor configuration for Ubuntu +- **PR [#74]** - Remove is_server from example +- **PR [#75]** - Add more settings for server and peer declarations +- **PR [#83]** - Fix apparmor spec tests + +## v1.6.8 (2014-12-04) + +- **PR [#81]** - Update to berkshelf3 + +## v1.6.6 (2014-12-02) + +- **PR [#76]** - Overhauled Testing +- **PR [#68]** - Updated Leapseconds +- **PR [#51]** - Berksfile source deprecation + +## v1.6.5 (2014-09-25) + +- Ensure that ntp version is captured + +## v1.6.4 (2014-07-02) + +- Leapseconds File Expired, update to 3626380800 +- **[COOK-3887](https://tickets.opscode.com/browse/COOK-3887)** - Trivial changes to achieve Gentoo support +- **[COOK-1876](https://tickets.opscode.com/browse/COOK-1876)** - ntp leapfile assumes ntpd >= 4.2.6 syntax + +## v1.6.2 (2014-03-19) + +- [COOK-4162] - change "No NTP servers specified" message to :debug + +## v1.6.0 (2014-02-21) + +### Improvement + +- **[COOK-4346](https://tickets.opscode.com/browse/COOK-4346)** - Solaris 11 support for ntp +- **[COOK-4339](https://tickets.opscode.com/browse/COOK-4339)** - Disable Monitoring by Default +- **[COOK-3604](https://tickets.opscode.com/browse/COOK-3604)** - Enable listening on specific interfaces + +### Bug + +- **[COOK-4106](https://tickets.opscode.com/browse/COOK-4106)** - Check for default content in ntp.conf +- **[COOK-4087](https://tickets.opscode.com/browse/COOK-4087)** - quote option in readme +- **[COOK-3797](https://tickets.opscode.com/browse/COOK-3797)** - Cookbook fails to upload due to 1.9.x syntax +- **[COOK-3023](https://tickets.opscode.com/browse/COOK-3023)** - NTP leapseconds file denied by Ubuntu apparmor profile + +## v1.5.4 (2013-12-29) + +[COOK-4007]- update to 3612902400 + +## v1.5.2 + +### Bug + +- **[COOK-3797](https://tickets.opscode.com/browse/COOK-3797)** - Add /spec to Chefignore + +## v1.5.0 + +### Improvement + +- **[COOK-3651](https://tickets.opscode.com/browse/COOK-3651)** - Refactor and clean up +- **[COOK-3630](https://tickets.opscode.com/browse/COOK-3630)** - Switch NTP cookbook linting from Tailor to Rubocop +- **[COOK-3273](https://tickets.opscode.com/browse/COOK-3273)** - Add tests + +### New Feature + +- **[COOK-3636](https://tickets.opscode.com/browse/COOK-3636)** - Allow ntp cookbook to update clock to ntp servers + +### Bug + +- **[COOK-3410](https://tickets.opscode.com/browse/COOK-3410)** - Remove redundant ntpdate/disable recipes +- **[COOK-1170](https://tickets.opscode.com/browse/COOK-1170)** - Allow redefining NTP servers in a role + +## v1.4.0 + +### Improvement + +- **[COOK-3365](https://tickets.opscode.com/browse/COOK-3365)** - Update ntp leapseconds file to version 3597177600 +- **[COOK-1674](https://tickets.opscode.com/browse/COOK-1674)** - Add Windows support + +## v1.3.2 + +- [COOK-2024] - update leapfile for IERS Bulletin C + +## v1.3.0 + +- [COOK-1404] - add leapfile for handling leap seconds + +## v1.2.0 + +- [COOK-1184] - Add recipe to disable NTP completely +- [COOK-1298] - Refactor into a reference cookbook for testing + +## v1.1.8 + +- [COOK-1158] - RHEL family >= 6 has ntpdate package + +## v1.1.6 + +- Related to changes in COOK-1124, fix group for freebsd and else + +## v1.1.4 + +- [COOK-1124] - parameterised driftfile and statsdir to be configurable by platform + +## v1.1.2 + +- [COOK-952] - freebsd support +- [COOK-949] - check for any virtual system not just vmware + +## v1.1.0 + +- Fixes COOK-376 (use LAN peers, iburst option, LAN restriction attribute) + +## v1.0.1 + +- Support scientific linux +- Use service name attribute in resource (fixes EL derivatives) diff --git a/cookbooks/yum-epel/CONTRIBUTING.md b/cookbooks/ntp/CONTRIBUTING.md similarity index 100% rename from cookbooks/yum-epel/CONTRIBUTING.md rename to cookbooks/ntp/CONTRIBUTING.md diff --git a/cookbooks/ntp/MAINTAINERS.md b/cookbooks/ntp/MAINTAINERS.md new file mode 100644 index 0000000..645ed14 --- /dev/null +++ b/cookbooks/ntp/MAINTAINERS.md @@ -0,0 +1,15 @@ + + +# Maintainers + +This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. + +Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. + +# Project Maintainer +* [Tim Smith](https://github.com/tas50) + +# Maintainers +* [Jennifer Davis](https://github.com/sigje) +* [Tim Smith](https://github.com/tas50) +* [Thom May](https://github.com/thommay) diff --git a/cookbooks/ntp/README.md b/cookbooks/ntp/README.md new file mode 100644 index 0000000..af671cb --- /dev/null +++ b/cookbooks/ntp/README.md @@ -0,0 +1,305 @@ +# NTP Cookbook + +[![Build Status](https://travis-ci.org/chef-cookbooks/ntp.svg?branch=master)](http://travis-ci.org/chef-cookbooks/ntp) [![Cookbook Version](https://img.shields.io/cookbook/v/ntp.svg)](https://supermarket.chef.io/cookbooks/ntp) + +Installs and configures ntp. On Windows systems it uses the Meinberg port of the standard NTPd client to Windows. + +## Requirements + +### Platforms + +- Debian-family Linux Distributions +- RedHat-family Linux Distributions +- Fedora +- Gentoo Linux +- openSUSE +- FreeBSD +- Windows 2008 R2+ +- Mac OS X 10.11+ + +### Chef + +- Chef 12.1+ + +### Cookbooks + +- none + +## Attributes + +### Recommended tunables + +- `ntp['servers']` - (applies to NTP Servers and Clients) + + - Array, should be a list of upstream NTP servers that will be considered authoritative by the local NTP daemon. The local NTP daemon will act as a client, adjusting local time to match time data retrieved from the upstream NTP servers. + + The NTP protocol works best with at least 4 servers. The ntp daemon will disregard any server after the 10th listed, but will continue monitoring all listed servers. For more information, see [Upstream Server Time Quantity](http://support.ntp.org/bin/view/Support/SelectingOffsiteNTPServers#Section_5.3.3.) at [support.ntp.org](http://support.ntp.org). + +- `ntp['peers']` - (applies to NTP Servers ONLY) + + - Array, should be a list of local NTP peers. For more information, see [Designing Your NTP Network](http://support.ntp.org/bin/view/Support/DesigningYourNTPNetwork) at [support.ntp.org](http://support.ntp.org). + +- `ntp['restrictions']` - (applies to NTP Servers only) + + - Array, should be a list of restrict lines to define access to NTP clients on your LAN. + +- `ntp['sync_clock']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to false. Forces the ntp daemon to be halted, an ntp -q command to be issued, and the ntp daemon to be restarted again on every Chef-client run. Will have no effect if drift is over 1000 seconds. + +- `ntp['sync_hw_clock']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to false. On *nix-based systems, forces the 'hwclock --systohc' command to be issued on every Chef-client run. This will sync the hardware clock to the system clock. + - Not available on Windows. + +- `ntp['restrict_default']` + + - String. Defaults to 'kod notrap nomodify nopeer noquery'. Set to 'ignore' to [further lock down access](http://support.ntp.org/bin/view/Support/AccessRestrictions#Section_6.5.1.1.2.). + +- `ntp["listen_network"]` / `ntp["listen"]` + + - String, optional attribute. Default is for NTP to listen on all addresses. + - `ntp["listen_network"]` should be set to 'primary' to listen on the node's primary IP address as determined by ohai, or set to a CIDR (eg: '192.168.4.0/24') to listen on the last node address on that CIDR. + - `ntp["listen"]` can be set to a specific address (eg: '192.168.4.10') instead of `ntp["listen_network"]` to force listening on a specific address. + - If both `ntp["listen"]` and `ntp["listen_network"]` are set then `ntp["listen"]` will always win. + +- `ntp["ignore"]` + + - Array, interface names to ignore from listening. Can be used to disable listening wildcard interfaces (eg: ['wildcard', '::1']), can be combined with `ntp["listen"]` + +- `ntp["statistics"]` + + - Boolean. Default to true. Enable/disable statistics data logging into `ntp['statsdir']`. + - Not available on Windows. + +- `ntp['conf_restart_immediate']` + + - Boolean. Defaults to false. Restarts NTP service immediately after a config update if true. Otherwise it is a delayed restart. + +- `ntp['peer']['disable_tinker_panic_on_virtualization_guest']` (applies to virtualized hosts only) + + - Boolean. Defaults to true. Sets tinker panic to 0\. NTP default it 1000\. (See p. 23 for explanation on disabling panic) (Note: this overrides `ntp['tinker']['panic']` attribute) + +- `ntp['peer']['use_iburst']` (applies to NTP Servers ONLY) + + - Boolean. Defaults to true. Enables iburst in peer declaration. + +- `ntp['peer']['use_burst']` (applies to NTP Servers ONLY) + + - Boolean. Defaults to false. Enables burst in peer declaration. + +- `ntp['peer']['minpoll']` (applies to NTP Servers ONLY) + + - Boolean. Defaults to 6 (ntp default). Specify the minimum poll intervals for NTP messages, in seconds to the power of two. + +- `ntp['peer']['maxpoll']` (applies to NTP Servers ONLY) + + - Boolean. Defaults to 10 (ntp default). Specify the maximum poll intervals for NTP messages, in seconds to the power of two. + +- `ntp['server']['prefer']` (applies to NTP Servers and Clients) + + - String. Defaults to emtpy string. The server from `ntp['servers']` to prefer getting the time from. + +- `ntp['server']['use_iburst']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to true. Enables iburst in server declaration. + +- `ntp['server']['use_burst']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to false. Enables burst in server declaration. + +- `ntp['server']['minpoll']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to 6 (ntp default). Specify the minimum poll intervals for NTP messages, in seconds to the power of two. + +- `ntp['server']['maxpoll']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to 10 (ntp default). Specify the maximum poll intervals for NTP messages, in seconds to the power of two. + +- `ntp['tinker']['allan']` + + - Number. Defaults to 1500 (ntp default). Spedifies the Allan intercept, which is a parameter of the PLL/FLL clock discipline algorithm, in seconds. + +- `ntp['tinker']['dispersion']` + + - Number. Defaults to 15 (ntp default). Specifies the dispersion increase rate in parts-per-million (PPM). + +- `ntp['tinker']['panic']` + + - Number. Defaults to 1000 (ntp default). Spedifies the panic threshold in seconds. If set to zero, the panic sanity check is disabled and a clock offset of any value will be accepted. + +- `ntp['tinker']['step']` + + - Number. Defaults to 0.128 (ntp default). Spedifies the step threshold in seconds. If set to zero, step adjustments will never occur. Note: The kernel time discipline is disabled if the step threshold is set to zero or greater than 0.5 s. + +- `ntp['tinker']['stepout']` + + - Number. Defaults to 900 (ntp default). Specifies the stepout threshold in seconds. If set to zero, popcorn spikes will not be suppressed. + +- `ntp['localhost']['noquery']` (applies to NTP Servers and Clients) + + - Boolean. Defaults to false. Set to true if using ntp < 4.2.8 or any unpatched ntp version to mitigate CVE-2014-9293 / CVE-2014-9294 / CVE-2014-9295 + +- `ntp['orphan']['enabled']` + + - Boolean, enables orphan mode if set to true + +- `ntp['orphan']['stratum']` + + - Number. Defaults to 5, recommended value for stratum is 2 more than the worst-case externally-reachable source of time + +### Automatically Set Attributes + +These attributes are set based on platform / system information provided by Ohai + +- `ntp['packages']` + + - Array, the packages to install + - Default, ntp for everything, ntpdate depending on platform. Not applicable for + - Windows nodes + +- `ntp['service']` + + - String, the service to act on + - Default, ntp, NTP, or ntpd, depending on platform + +- `ntp['varlibdir']` + + - String, the path to /var/lib files such as the driftfile. + - Default, platform-specific location. Not applicable for Windows nodes + +- `ntp['driftfile']` + + - String, the path to the frequency file. + - Default, platform-specific location. + +- `ntp['conffile']` + + - String, the path to the ntp configuration file. + - Default, platform-specific location. + +- `ntp['statsdir']` + + - String, the directory path for files created by the statistics facility. + - Default, platform-specific location. Not applicable for Windows nodes + +- `ntp['conf_owner'] and ntp['conf_group']` + + - String, the owner and group of the sysconf directory files, such as /etc/ntp.conf. + - Default, platform-specific root:root or root:wheel. + +- `ntp['var_owner'] and ntp['var_group']` + + - String, the owner and group of the /var/lib directory files, such as /var/lib/ntp. + - Default, platform-specific ntp:ntp or root:wheel. Not applicable for Windows nodes + +- `ntp['leapfile']` + + - String, the path to the ntp leapfile. + - Default, /etc/ntp.leapseconds. + +- `ntp['package_url']` + + - String, the URL to the the Meinberg NTPd client installation package. + - Default, Meinberg site download URL + - Windows platform only + +- `ntp['vs_runtime_url']` + + - String, the URL to the the Visual Studio C++ 2008 runtime libraries that are required for the Meinberg NTP client. + - Default, Microsoft site download URL + - Windows platform only + +- `ntp['vs_runtime_productname']` + + - String, the installation name of the Visual Studio C++ Runtimes file. + - Default, "Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022" + - Windows platform only + +- `ntp['sync_hw_clock']` + + - Boolean, determines if the ntpdate command is issued to sync the hardware clock + - Default, false + - Not applicable for Windows nodes + +- `ntp['apparmor_enabled']` + + - Boolean, enables configuration of apparmor if set to true + - Defaults to false and will make no provisions for apparmor. + - If a platform has apparmor enabled (currently Ubuntu) default will become true. + +- `ntp['use_cmos']` + + - Boolean, uses a high stratum undisciplined clock for machines with real CMOS clock. + - Defaults to true unless a platform appears to be virtualized according to Ohai. + +## Usage + +### default recipe + +Set up the ntp attributes in a role. For example in a base.rb role applied to all nodes: + +```ruby +name 'base' +description 'Role applied to all systems' +default_attributes( + 'ntp' => { + 'servers' => ['time0.int.example.org', 'time1.int.example.org'] + } +) +``` + +Then in an ntpserver.rb role that is applied to NTP servers (e.g., time.int.example.org): + +```ruby +name 'ntp_server' +description 'Role applied to the system that should be an NTP server.' +default_attributes( + 'ntp' => { + 'servers' => ['0.pool.ntp.org', '1.pool.ntp.org'], + 'peers' => ['time0.int.example.org', 'time1.int.example.org'], + 'restrictions' => ['10.0.0.0 mask 255.0.0.0 nomodify notrap'] + } +) +``` + +The timeX.int.example.org used in these roles should be the names or IP addresses of internal NTP servers. Then simply add ntp, or `ntp::default` to your run_list to apply the ntp daemon's configuration. + +### windows_client recipe + +Windows only. Apply on a Windows host to install the Meinberg NTPd client. + +### mac_os_x_client recipe + +Mac OS X only. Apply on a Mac OS X host to configure NTP. + +## License & Authors + +- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io)) +- Contributor:: Eric G. Wolfe ([wolfe21@marshall.edu](mailto:wolfe21@marshall.edu)) +- Contributor:: Fletcher Nichol ([fletcher@nichol.ca](mailto:fletcher@nichol.ca)) +- Contributor:: Tim Smith ([tsmith@chef.io](mailto:tsmith@chef.io)) +- Contributor:: Charles Johnson ([charles@chef.io](mailto:charles@chef.io)) +- Contributor:: Brad Knowles ([bknowles@momentumsi.com](mailto:bknowles@momentumsi.com)) + +```text +Copyright 2009-2016, Chef Software, Inc. +Copyright 2012, Eric G. Wolfe +Copyright 2012, Fletcher Nichol +Copyright 2012, Webtrends, Inc. +Copyright 2013, Limelight Networks, Inc. +Copyright 2013, Brad Knowles +Copyright 2013, Brad Beam + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/cookbooks/ntp/attributes/default.rb b/cookbooks/ntp/attributes/default.rb new file mode 100644 index 0000000..671a974 --- /dev/null +++ b/cookbooks/ntp/attributes/default.rb @@ -0,0 +1,130 @@ +# +# Cookbook:: ntp +# Attributes:: default +# +# Author:: Joshua Timberman () +# Author:: Tim Smith () +# Author:: Charles Johnson () +# +# Copyright:: 2009-2017, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# default attributes for all platforms +default['ntp']['servers'] = [] # The default recipe sets a list of common NTP servers (COOK-1170) +default['ntp']['peers'] = [] +default['ntp']['restrictions'] = [] +default['ntp']['tinker'] = { 'panic' => 0 } + +# set `restrict default` for IPv4 and IPv6 +default['ntp']['restrict_default'] = 'kod notrap nomodify nopeer noquery' + +# internal attributes +default['ntp']['packages'] = %w(ntp) +default['ntp']['service'] = 'ntpd' +default['ntp']['varlibdir'] = '/var/lib/ntp' +default['ntp']['driftfile'] = "#{node['ntp']['varlibdir']}/ntp.drift" +default['ntp']['logfile'] = nil +default['ntp']['conffile'] = '/etc/ntp.conf' +default['ntp']['statsdir'] = '/var/log/ntpstats/' +default['ntp']['conf_owner'] = 'root' +default['ntp']['conf_group'] = 'root' +default['ntp']['var_owner'] = 'ntp' +default['ntp']['var_group'] = 'ntp' +default['ntp']['leapfile'] = '/etc/ntp.leapseconds' +default['ntp']['sync_clock'] = false +default['ntp']['sync_hw_clock'] = false +default['ntp']['listen'] = nil +default['ntp']['listen_network'] = nil +default['ntp']['ignore'] = nil +default['ntp']['apparmor_enabled'] = false +default['ntp']['monitor'] = false +default['ntp']['statistics'] = true +default['ntp']['conf_restart_immediate'] = false +default['ntp']['keys'] = nil +default['ntp']['trustedkey'] = nil +default['ntp']['requestkey'] = nil + +# See http://www.vmware.com/vmtn/resources/238 p. 23 for explanation +default['ntp']['disable_tinker_panic_on_virtualization_guest'] = true + +default['ntp']['peer']['key'] = nil +default['ntp']['peer']['use_iburst'] = true +default['ntp']['peer']['use_burst'] = false +default['ntp']['peer']['minpoll'] = 6 +default['ntp']['peer']['maxpoll'] = 10 + +default['ntp']['server']['prefer'] = '' +default['ntp']['server']['use_iburst'] = true +default['ntp']['server']['use_burst'] = false +default['ntp']['server']['minpoll'] = 6 +default['ntp']['server']['maxpoll'] = 10 + +default['ntp']['tinker']['allan'] = 1500 +default['ntp']['tinker']['dispersion'] = 15 +default['ntp']['tinker']['panic'] = 1000 +default['ntp']['tinker']['step'] = 0.128 +default['ntp']['tinker']['stepout'] = 900 + +default['ntp']['orphan']['enabled'] = false +default['ntp']['orphan']['stratum'] = 5 # ntp recommends 2 more than the worst-case externally-reachable source of time + +# Set to true if using ntp < 4.2.8 or any unpatched ntp version to mitigate CVE-2014-9293 / CVE-2014-9294 / CVE-2014-9295 +default['ntp']['localhost']['noquery'] = false + +# overrides on a platform-by-platform basis +case node['platform_family'] +when 'debian' + default['ntp']['service'] = 'ntp' + default['ntp']['apparmor_enabled'] = true if File.exist? '/etc/init.d/apparmor' +when 'rhel', 'fedora' + default['ntp']['packages'] = %w(ntp ntpdate) if node['platform_version'].to_i >= 7 +when 'windows' + default['ntp']['service'] = 'NTP' + default['ntp']['driftfile'] = 'C:\\NTP\\ntp.drift' + default['ntp']['conffile'] = 'C:\\NTP\\etc\\ntp.conf' + default['ntp']['conf_owner'] = 'Administrators' + default['ntp']['conf_group'] = 'Administrators' + default['ntp']['package_url'] = 'https://www.meinbergglobal.com/download/ntp/windows/ntp-4.2.8p5-win32-setup.exe' + default['ntp']['statistics'] = false +when 'freebsd' + default['ntp']['varlibdir'] = '/var/db' + default['ntp']['driftfile'] = "#{node['ntp']['varlibdir']}/ntpd.drift" + default['ntp']['statsdir'] = "#{node['ntp']['varlibdir']}/ntpstats" + default['ntp']['conf_group'] = 'wheel' + default['ntp']['var_owner'] = 'root' + default['ntp']['var_group'] = 'wheel' +when 'gentoo' + default['ntp']['leapfile'] = "#{node['ntp']['varlibdir']}/ntp.leapseconds" +when 'solaris2' + default['ntp']['service'] = 'ntp' + default['ntp']['varlibdir'] = '/var/ntp' + default['ntp']['conffile'] = '/etc/inet/ntp.conf' + default['ntp']['statsdir'] = "#{node['ntp']['varlibdir']}/ntpstats/" + default['ntp']['conf_owner'] = 'root' + default['ntp']['conf_group'] = 'root' + default['ntp']['var_owner'] = 'root' + default['ntp']['var_group'] = 'sys' + default['ntp']['leapfile'] = '/etc/inet/ntp.leap' +when 'pld' + default['ntp']['packages'] = %w(ntpd) + default['ntp']['conffile'] = '/etc/ntp/ntp.conf' + default['ntp']['leapfile'] = '/etc/ntp/ntp.leapseconds' + default['ntp']['driftfile'] = "#{node['ntp']['varlibdir']}/drift" + default['ntp']['var_owner'] = 'root' +end + +unless node['platform'] == 'windows' + default['ntp']['use_cmos'] = !node['virtualization'] || node['virtualization']['role'] != 'guest' ? true : false +end diff --git a/cookbooks/ntp/files/default/ntp.ini b/cookbooks/ntp/files/default/ntp.ini new file mode 100644 index 0000000..11498b4 --- /dev/null +++ b/cookbooks/ntp/files/default/ntp.ini @@ -0,0 +1,23 @@ +[Installer] +InstallDir=C:\NTP +UpgradeMode=Reinstall +Logfile=C:\NTP\install.log +Silent=yes + +[Components] +InstallDocs=yes +InstallTools=yes +InstallOpenSSL=yes +CreateStartMenuEntries=yes + +[Service] +ModifyFirewall=yes +ServiceAccount=@SYSTEM +DisableOthers=yes +AllowBigInitialTimestep=yes +EnableMMTimer=yes +AutoStart=yes +StartAfterInstallation=yes + +[Configuration] +UseConfigFile=C:\NTP\ntp.conf diff --git a/cookbooks/ntp/files/default/ntp.leapseconds b/cookbooks/ntp/files/default/ntp.leapseconds new file mode 100644 index 0000000..22fa785 --- /dev/null +++ b/cookbooks/ntp/files/default/ntp.leapseconds @@ -0,0 +1,250 @@ +# +# In the following text, the symbol '#' introduces +# a comment, which continues from that symbol until +# the end of the line. A plain comment line has a +# whitespace character following the comment indicator. +# There are also special comment lines defined below. +# A special comment will always have a non-whitespace +# character in column 2. +# +# A blank line should be ignored. +# +# The following table shows the corrections that must +# be applied to compute International Atomic Time (TAI) +# from the Coordinated Universal Time (UTC) values that +# are transmitted by almost all time services. +# +# The first column shows an epoch as a number of seconds +# since 1 January 1900, 00:00:00 (1900.0 is also used to +# indicate the same epoch.) Both of these time stamp formats +# ignore the complexities of the time scales that were +# used before the current definition of UTC at the start +# of 1972. (See note 3 below.) +# The second column shows the number of seconds that +# must be added to UTC to compute TAI for any timestamp +# at or after that epoch. The value on each line is +# valid from the indicated initial instant until the +# epoch given on the next one or indefinitely into the +# future if there is no next line. +# (The comment on each line shows the representation of +# the corresponding initial epoch in the usual +# day-month-year format. The epoch always begins at +# 00:00:00 UTC on the indicated day. See Note 5 below.) +# +# Important notes: +# +# 1. Coordinated Universal Time (UTC) is often referred to +# as Greenwich Mean Time (GMT). The GMT time scale is no +# longer used, and the use of GMT to designate UTC is +# discouraged. +# +# 2. The UTC time scale is realized by many national +# laboratories and timing centers. Each laboratory +# identifies its realization with its name: Thus +# UTC(NIST), UTC(USNO), etc. The differences among +# these different realizations are typically on the +# order of a few nanoseconds (i.e., 0.000 000 00x s) +# and can be ignored for many purposes. These differences +# are tabulated in Circular T, which is published monthly +# by the International Bureau of Weights and Measures +# (BIPM). See www.bipm.org for more information. +# +# 3. The current definition of the relationship between UTC +# and TAI dates from 1 January 1972. A number of different +# time scales were in use before that epoch, and it can be +# quite difficult to compute precise timestamps and time +# intervals in those "prehistoric" days. For more information, +# consult: +# +# The Explanatory Supplement to the Astronomical +# Ephemeris. +# or +# Terry Quinn, "The BIPM and the Accurate Measurement +# of Time," Proc. of the IEEE, Vol. 79, pp. 894-905, +# July, 1991. +# +# 4. The decision to insert a leap second into UTC is currently +# the responsibility of the International Earth Rotation and +# Reference Systems Service. (The name was changed from the +# International Earth Rotation Service, but the acronym IERS +# is still used.) +# +# Leap seconds are announced by the IERS in its Bulletin C. +# +# See www.iers.org for more details. +# +# Every national laboratory and timing center uses the +# data from the BIPM and the IERS to construct UTC(lab), +# their local realization of UTC. +# +# Although the definition also includes the possibility +# of dropping seconds ("negative" leap seconds), this has +# never been done and is unlikely to be necessary in the +# foreseeable future. +# +# 5. If your system keeps time as the number of seconds since +# some epoch (e.g., NTP timestamps), then the algorithm for +# assigning a UTC time stamp to an event that happens during a positive +# leap second is not well defined. The official name of that leap +# second is 23:59:60, but there is no way of representing that time +# in these systems. +# Many systems of this type effectively stop the system clock for +# one second during the leap second and use a time that is equivalent +# to 23:59:59 UTC twice. For these systems, the corresponding TAI +# timestamp would be obtained by advancing to the next entry in the +# following table when the time equivalent to 23:59:59 UTC +# is used for the second time. Thus the leap second which +# occurred on 30 June 1972 at 23:59:59 UTC would have TAI +# timestamps computed as follows: +# +# ... +# 30 June 1972 23:59:59 (2287785599, first time): TAI= UTC + 10 seconds +# 30 June 1972 23:59:60 (2287785599,second time): TAI= UTC + 11 seconds +# 1 July 1972 00:00:00 (2287785600) TAI= UTC + 11 seconds +# ... +# +# If your system realizes the leap second by repeating 00:00:00 UTC twice +# (this is possible but not usual), then the advance to the next entry +# in the table must occur the second time that a time equivalent to +# 00:00:00 UTC is used. Thus, using the same example as above: +# +# ... +# 30 June 1972 23:59:59 (2287785599): TAI= UTC + 10 seconds +# 30 June 1972 23:59:60 (2287785600, first time): TAI= UTC + 10 seconds +# 1 July 1972 00:00:00 (2287785600,second time): TAI= UTC + 11 seconds +# ... +# +# in both cases the use of timestamps based on TAI produces a smooth +# time scale with no discontinuity in the time interval. However, +# although the long-term behavior of the time scale is correct in both +# methods, the second method is technically not correct because it adds +# the extra second to the wrong day. +# +# This complexity would not be needed for negative leap seconds (if they +# are ever used). The UTC time would skip 23:59:59 and advance from +# 23:59:58 to 00:00:00 in that case. The TAI offset would decrease by +# 1 second at the same instant. This is a much easier situation to deal +# with, since the difficulty of unambiguously representing the epoch +# during the leap second does not arise. +# +# Some systems implement leap seconds by amortizing the leap second +# over the last few minutes of the day. The frequency of the local +# clock is decreased (or increased) to realize the positive (or +# negative) leap second. This method removes the time step described +# above. Although the long-term behavior of the time scale is correct +# in this case, this method introduces an error during the adjustment +# period both in time and in frequency with respect to the official +# definition of UTC. +# +# Questions or comments to: +# Judah Levine +# Time and Frequency Division +# NIST +# Boulder, Colorado +# Judah.Levine@nist.gov +# +# Last Update of leap second values: 8 July 2016 +# +# The following line shows this last update date in NTP timestamp +# format. This is the date on which the most recent change to +# the leap second data was added to the file. This line can +# be identified by the unique pair of characters in the first two +# columns as shown below. +# +#$ 3676924800 +# +# The NTP timestamps are in units of seconds since the NTP epoch, +# which is 1 January 1900, 00:00:00. The Modified Julian Day number +# corresponding to the NTP time stamp, X, can be computed as +# +# X/86400 + 15020 +# +# where the first term converts seconds to days and the second +# term adds the MJD corresponding to the time origin defined above. +# The integer portion of the result is the integer MJD for that +# day, and any remainder is the time of day, expressed as the +# fraction of the day since 0 hours UTC. The conversion from day +# fraction to seconds or to hours, minutes, and seconds may involve +# rounding or truncation, depending on the method used in the +# computation. +# +# The data in this file will be updated periodically as new leap +# seconds are announced. In addition to being entered on the line +# above, the update time (in NTP format) will be added to the basic +# file name leap-seconds to form the name leap-seconds.. +# In addition, the generic name leap-seconds.list will always point to +# the most recent version of the file. +# +# This update procedure will be performed only when a new leap second +# is announced. +# +# The following entry specifies the expiration date of the data +# in this file in units of seconds since the origin at the instant +# 1 January 1900, 00:00:00. This expiration date will be changed +# at least twice per year whether or not a new leap second is +# announced. These semi-annual changes will be made no later +# than 1 June and 1 December of each year to indicate what +# action (if any) is to be taken on 30 June and 31 December, +# respectively. (These are the customary effective dates for new +# leap seconds.) This expiration date will be identified by a +# unique pair of characters in columns 1 and 2 as shown below. +# In the unlikely event that a leap second is announced with an +# effective date other than 30 June or 31 December, then this +# file will be edited to include that leap second as soon as it is +# announced or at least one month before the effective date +# (whichever is later). +# If an announcement by the IERS specifies that no leap second is +# scheduled, then only the expiration date of the file will +# be advanced to show that the information in the file is still +# current -- the update time stamp, the data and the name of the file +# will not change. +# +# Updated through IERS Bulletin C52 +# File expires on: 28 June 2017 +# +#@ 3707596800 +# +2272060800 10 # 1 Jan 1972 +2287785600 11 # 1 Jul 1972 +2303683200 12 # 1 Jan 1973 +2335219200 13 # 1 Jan 1974 +2366755200 14 # 1 Jan 1975 +2398291200 15 # 1 Jan 1976 +2429913600 16 # 1 Jan 1977 +2461449600 17 # 1 Jan 1978 +2492985600 18 # 1 Jan 1979 +2524521600 19 # 1 Jan 1980 +2571782400 20 # 1 Jul 1981 +2603318400 21 # 1 Jul 1982 +2634854400 22 # 1 Jul 1983 +2698012800 23 # 1 Jul 1985 +2776982400 24 # 1 Jan 1988 +2840140800 25 # 1 Jan 1990 +2871676800 26 # 1 Jan 1991 +2918937600 27 # 1 Jul 1992 +2950473600 28 # 1 Jul 1993 +2982009600 29 # 1 Jul 1994 +3029443200 30 # 1 Jan 1996 +3076704000 31 # 1 Jul 1997 +3124137600 32 # 1 Jan 1999 +3345062400 33 # 1 Jan 2006 +3439756800 34 # 1 Jan 2009 +3550089600 35 # 1 Jul 2012 +3644697600 36 # 1 Jul 2015 +3692217600 37 # 1 Jan 2017 +# +# the following special comment contains the +# hash value of the data in this file computed +# use the secure hash algorithm as specified +# by FIPS 180-1. See the files in ~/pub/sha for +# the details of how this hash value is +# computed. Note that the hash computation +# ignores comments and whitespace characters +# in data lines. It includes the NTP values +# of both the last modification time and the +# expiration time of the file, but not the +# white space on those lines. +# the hash line is also ignored in the +# computation. +# +#h dacf2c42 2c4765d6 3c797af8 2cf630eb 699c8c67 diff --git a/cookbooks/ntp/files/default/usr.sbin.ntpd.apparmor b/cookbooks/ntp/files/default/usr.sbin.ntpd.apparmor new file mode 100644 index 0000000..7dfbeb0 --- /dev/null +++ b/cookbooks/ntp/files/default/usr.sbin.ntpd.apparmor @@ -0,0 +1,88 @@ +# vim:syntax=apparmor +# +# Maintained by Chef +# +# Updated for Ubuntu by: Jamie Strandboge +# ------------------------------------------------------------------ +# +# Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2009-2012 Canonical Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +# +# ------------------------------------------------------------------ + +#include +#include +/usr/sbin/ntpd { + #include + #include + #include + + capability ipc_lock, + capability net_bind_service, + capability setgid, + capability setuid, + capability sys_chroot, + capability sys_resource, + capability sys_time, + capability sys_nice, + + network inet dgram, + network inet6 dgram, + network inet stream, + network inet6 stream, + + @{PROC}/net/if_inet6 r, + @{PROC}/*/net/if_inet6 r, + @{NTPD_DEVICE} rw, + + /{,s}bin/ r, + /usr/{,s}bin/ r, + /usr/local/{,s}bin/ r, + /usr/sbin/ntpd rmix, + + /opt/chef/embedded/bin/ r, + + /etc/ntp.conf r, + /etc/ntp.conf.dhcp r, + /etc/ntpd.conf r, + /etc/ntpd.conf.tmp r, + /var/lib/ntp/ntp.conf.dhcp r, + + /etc/ntp.leapseconds r, + + /etc/ntp.keys r, + /etc/ntp/** r, + + /etc/ntp.drift rwl, + /etc/ntp.drift.TEMP rwl, + /etc/ntp/drift* rwl, + /var/lib/ntp/*drift rw, + /var/lib/ntp/*drift.TEMP rw, + + /var/log/ntp w, + /var/log/ntp.log w, + /var/log/ntpd w, + /var/log/ntpstats/clockstats* rwl, + /var/log/ntpstats/loopstats* rwl, + /var/log/ntpstats/peerstats* rwl, + /var/log/ntpstats/rawstats* rwl, + /var/log/ntpstats/sysstats* rwl, + + /{,var/}run/ntpd.pid w, + + # samba4 ntp signing socket + /{,var/}run/samba/ntp_signd/socket rw, + + # For use with clocks that report via shared memory (e.g. gpsd), + # you may need to give ntpd access to all of shared memory, though + # this can be considered dangerous. See https://launchpad.net/bugs/722815 + # for details. To enable, add this to local/usr.sbin.ntpd: + # capability ipc_owner, + + # Site-specific additions and overrides. See local/README for details. + #include +} diff --git a/cookbooks/ntp/libraries/ntp_helper.rb b/cookbooks/ntp/libraries/ntp_helper.rb new file mode 100644 index 0000000..8560994 --- /dev/null +++ b/cookbooks/ntp/libraries/ntp_helper.rb @@ -0,0 +1,49 @@ +# +# Author:: Julian C. Dunn () +# Cookbook:: ntp +# Library:: helper +# +# Copyright:: 2014-2017, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'chef/mixin/shell_out' + +module Opscode + module Ntp + # Helper methods for ntp + module Helper + include Chef::Mixin::ShellOut + + def ntpd_supports_native_leapfiles + ntpd_version = determine_ntpd_version + if ntpd_version + ntpd_version =~ /ntpd.*(\d+\.\d+\.\d+)/ + # Abuse of Gem::Requirement, but it works + Gem::Requirement.new('>= 4.2.6').satisfied_by?(Gem::Version.new(Regexp.last_match(1))) + else + false + end + end + + private + + def determine_ntpd_version + cmd = shell_out!('ntpd --version 2>&1') + cmd.stdout.strip + rescue Errno::ENOENT, Mixlib::ShellOut::ShellCommandFailed + nil + end + end + end +end diff --git a/cookbooks/ntp/metadata.json b/cookbooks/ntp/metadata.json new file mode 100644 index 0000000..8791de2 --- /dev/null +++ b/cookbooks/ntp/metadata.json @@ -0,0 +1 @@ +{"name":"ntp","version":"3.4.0","description":"Installs and configures ntp as a client or server","long_description":"# NTP Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/ntp.svg?branch=master)](http://travis-ci.org/chef-cookbooks/ntp) [![Cookbook Version](https://img.shields.io/cookbook/v/ntp.svg)](https://supermarket.chef.io/cookbooks/ntp)\n\nInstalls and configures ntp. On Windows systems it uses the Meinberg port of the standard NTPd client to Windows.\n\n## Requirements\n\n### Platforms\n\n- Debian-family Linux Distributions\n- RedHat-family Linux Distributions\n- Fedora\n- Gentoo Linux\n- openSUSE\n- FreeBSD\n- Windows 2008 R2+\n- Mac OS X 10.11+\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- none\n\n## Attributes\n\n### Recommended tunables\n\n- `ntp['servers']` - (applies to NTP Servers and Clients)\n\n - Array, should be a list of upstream NTP servers that will be considered authoritative by the local NTP daemon. The local NTP daemon will act as a client, adjusting local time to match time data retrieved from the upstream NTP servers.\n\n The NTP protocol works best with at least 4 servers. The ntp daemon will disregard any server after the 10th listed, but will continue monitoring all listed servers. For more information, see [Upstream Server Time Quantity](http://support.ntp.org/bin/view/Support/SelectingOffsiteNTPServers#Section_5.3.3.) at [support.ntp.org](http://support.ntp.org).\n\n- `ntp['peers']` - (applies to NTP Servers ONLY)\n\n - Array, should be a list of local NTP peers. For more information, see [Designing Your NTP Network](http://support.ntp.org/bin/view/Support/DesigningYourNTPNetwork) at [support.ntp.org](http://support.ntp.org).\n\n- `ntp['restrictions']` - (applies to NTP Servers only)\n\n - Array, should be a list of restrict lines to define access to NTP clients on your LAN.\n\n- `ntp['sync_clock']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to false. Forces the ntp daemon to be halted, an ntp -q command to be issued, and the ntp daemon to be restarted again on every Chef-client run. Will have no effect if drift is over 1000 seconds.\n\n- `ntp['sync_hw_clock']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to false. On *nix-based systems, forces the 'hwclock --systohc' command to be issued on every Chef-client run. This will sync the hardware clock to the system clock.\n - Not available on Windows.\n\n- `ntp['restrict_default']`\n\n - String. Defaults to 'kod notrap nomodify nopeer noquery'. Set to 'ignore' to [further lock down access](http://support.ntp.org/bin/view/Support/AccessRestrictions#Section_6.5.1.1.2.).\n\n- `ntp[\"listen_network\"]` / `ntp[\"listen\"]`\n\n - String, optional attribute. Default is for NTP to listen on all addresses.\n - `ntp[\"listen_network\"]` should be set to 'primary' to listen on the node's primary IP address as determined by ohai, or set to a CIDR (eg: '192.168.4.0/24') to listen on the last node address on that CIDR.\n - `ntp[\"listen\"]` can be set to a specific address (eg: '192.168.4.10') instead of `ntp[\"listen_network\"]` to force listening on a specific address.\n - If both `ntp[\"listen\"]` and `ntp[\"listen_network\"]` are set then `ntp[\"listen\"]` will always win.\n\n- `ntp[\"ignore\"]`\n\n - Array, interface names to ignore from listening. Can be used to disable listening wildcard interfaces (eg: ['wildcard', '::1']), can be combined with `ntp[\"listen\"]`\n\n- `ntp[\"statistics\"]`\n\n - Boolean. Default to true. Enable/disable statistics data logging into `ntp['statsdir']`.\n - Not available on Windows.\n\n- `ntp['conf_restart_immediate']`\n\n - Boolean. Defaults to false. Restarts NTP service immediately after a config update if true. Otherwise it is a delayed restart.\n\n- `ntp['peer']['disable_tinker_panic_on_virtualization_guest']` (applies to virtualized hosts only)\n\n - Boolean. Defaults to true. Sets tinker panic to 0\\. NTP default it 1000\\. (See p. 23 for explanation on disabling panic) (Note: this overrides `ntp['tinker']['panic']` attribute)\n\n- `ntp['peer']['use_iburst']` (applies to NTP Servers ONLY)\n\n - Boolean. Defaults to true. Enables iburst in peer declaration.\n\n- `ntp['peer']['use_burst']` (applies to NTP Servers ONLY)\n\n - Boolean. Defaults to false. Enables burst in peer declaration.\n\n- `ntp['peer']['minpoll']` (applies to NTP Servers ONLY)\n\n - Boolean. Defaults to 6 (ntp default). Specify the minimum poll intervals for NTP messages, in seconds to the power of two.\n\n- `ntp['peer']['maxpoll']` (applies to NTP Servers ONLY)\n\n - Boolean. Defaults to 10 (ntp default). Specify the maximum poll intervals for NTP messages, in seconds to the power of two.\n\n- `ntp['server']['prefer']` (applies to NTP Servers and Clients)\n\n - String. Defaults to emtpy string. The server from `ntp['servers']` to prefer getting the time from.\n\n- `ntp['server']['use_iburst']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to true. Enables iburst in server declaration.\n\n- `ntp['server']['use_burst']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to false. Enables burst in server declaration.\n\n- `ntp['server']['minpoll']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to 6 (ntp default). Specify the minimum poll intervals for NTP messages, in seconds to the power of two.\n\n- `ntp['server']['maxpoll']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to 10 (ntp default). Specify the maximum poll intervals for NTP messages, in seconds to the power of two.\n\n- `ntp['tinker']['allan']`\n\n - Number. Defaults to 1500 (ntp default). Spedifies the Allan intercept, which is a parameter of the PLL/FLL clock discipline algorithm, in seconds.\n\n- `ntp['tinker']['dispersion']`\n\n - Number. Defaults to 15 (ntp default). Specifies the dispersion increase rate in parts-per-million (PPM).\n\n- `ntp['tinker']['panic']`\n\n - Number. Defaults to 1000 (ntp default). Spedifies the panic threshold in seconds. If set to zero, the panic sanity check is disabled and a clock offset of any value will be accepted.\n\n- `ntp['tinker']['step']`\n\n - Number. Defaults to 0.128 (ntp default). Spedifies the step threshold in seconds. If set to zero, step adjustments will never occur. Note: The kernel time discipline is disabled if the step threshold is set to zero or greater than 0.5 s.\n\n- `ntp['tinker']['stepout']`\n\n - Number. Defaults to 900 (ntp default). Specifies the stepout threshold in seconds. If set to zero, popcorn spikes will not be suppressed.\n\n- `ntp['localhost']['noquery']` (applies to NTP Servers and Clients)\n\n - Boolean. Defaults to false. Set to true if using ntp < 4.2.8 or any unpatched ntp version to mitigate CVE-2014-9293 / CVE-2014-9294 / CVE-2014-9295\n\n- `ntp['orphan']['enabled']`\n\n - Boolean, enables orphan mode if set to true\n\n- `ntp['orphan']['stratum']`\n\n - Number. Defaults to 5, recommended value for stratum is 2 more than the worst-case externally-reachable source of time\n\n### Automatically Set Attributes\n\nThese attributes are set based on platform / system information provided by Ohai\n\n- `ntp['packages']`\n\n - Array, the packages to install\n - Default, ntp for everything, ntpdate depending on platform. Not applicable for\n - Windows nodes\n\n- `ntp['service']`\n\n - String, the service to act on\n - Default, ntp, NTP, or ntpd, depending on platform\n\n- `ntp['varlibdir']`\n\n - String, the path to /var/lib files such as the driftfile.\n - Default, platform-specific location. Not applicable for Windows nodes\n\n- `ntp['driftfile']`\n\n - String, the path to the frequency file.\n - Default, platform-specific location.\n\n- `ntp['conffile']`\n\n - String, the path to the ntp configuration file.\n - Default, platform-specific location.\n\n- `ntp['statsdir']`\n\n - String, the directory path for files created by the statistics facility.\n - Default, platform-specific location. Not applicable for Windows nodes\n\n- `ntp['conf_owner'] and ntp['conf_group']`\n\n - String, the owner and group of the sysconf directory files, such as /etc/ntp.conf.\n - Default, platform-specific root:root or root:wheel.\n\n- `ntp['var_owner'] and ntp['var_group']`\n\n - String, the owner and group of the /var/lib directory files, such as /var/lib/ntp.\n - Default, platform-specific ntp:ntp or root:wheel. Not applicable for Windows nodes\n\n- `ntp['leapfile']`\n\n - String, the path to the ntp leapfile.\n - Default, /etc/ntp.leapseconds.\n\n- `ntp['package_url']`\n\n - String, the URL to the the Meinberg NTPd client installation package.\n - Default, Meinberg site download URL\n - Windows platform only\n\n- `ntp['vs_runtime_url']`\n\n - String, the URL to the the Visual Studio C++ 2008 runtime libraries that are required for the Meinberg NTP client.\n - Default, Microsoft site download URL\n - Windows platform only\n\n- `ntp['vs_runtime_productname']`\n\n - String, the installation name of the Visual Studio C++ Runtimes file.\n - Default, \"Microsoft Visual C++ 2008 Redistributable - x86 9.0.21022\"\n - Windows platform only\n\n- `ntp['sync_hw_clock']`\n\n - Boolean, determines if the ntpdate command is issued to sync the hardware clock\n - Default, false\n - Not applicable for Windows nodes\n\n- `ntp['apparmor_enabled']`\n\n - Boolean, enables configuration of apparmor if set to true\n - Defaults to false and will make no provisions for apparmor.\n - If a platform has apparmor enabled (currently Ubuntu) default will become true.\n\n- `ntp['use_cmos']`\n\n - Boolean, uses a high stratum undisciplined clock for machines with real CMOS clock.\n - Defaults to true unless a platform appears to be virtualized according to Ohai.\n\n## Usage\n\n### default recipe\n\nSet up the ntp attributes in a role. For example in a base.rb role applied to all nodes:\n\n```ruby\nname 'base'\ndescription 'Role applied to all systems'\ndefault_attributes(\n 'ntp' => {\n 'servers' => ['time0.int.example.org', 'time1.int.example.org']\n }\n)\n```\n\nThen in an ntpserver.rb role that is applied to NTP servers (e.g., time.int.example.org):\n\n```ruby\nname 'ntp_server'\ndescription 'Role applied to the system that should be an NTP server.'\ndefault_attributes(\n 'ntp' => {\n 'servers' => ['0.pool.ntp.org', '1.pool.ntp.org'],\n 'peers' => ['time0.int.example.org', 'time1.int.example.org'],\n 'restrictions' => ['10.0.0.0 mask 255.0.0.0 nomodify notrap']\n }\n)\n```\n\nThe timeX.int.example.org used in these roles should be the names or IP addresses of internal NTP servers. Then simply add ntp, or `ntp::default` to your run_list to apply the ntp daemon's configuration.\n\n### windows_client recipe\n\nWindows only. Apply on a Windows host to install the Meinberg NTPd client.\n\n### mac_os_x_client recipe\n\nMac OS X only. Apply on a Mac OS X host to configure NTP.\n\n## License & Authors\n\n- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))\n- Contributor:: Eric G. Wolfe ([wolfe21@marshall.edu](mailto:wolfe21@marshall.edu))\n- Contributor:: Fletcher Nichol ([fletcher@nichol.ca](mailto:fletcher@nichol.ca))\n- Contributor:: Tim Smith ([tsmith@chef.io](mailto:tsmith@chef.io))\n- Contributor:: Charles Johnson ([charles@chef.io](mailto:charles@chef.io))\n- Contributor:: Brad Knowles ([bknowles@momentumsi.com](mailto:bknowles@momentumsi.com))\n\n```text\nCopyright 2009-2016, Chef Software, Inc.\nCopyright 2012, Eric G. Wolfe\nCopyright 2012, Fletcher Nichol\nCopyright 2012, Webtrends, Inc.\nCopyright 2013, Limelight Networks, Inc.\nCopyright 2013, Brad Knowles\nCopyright 2013, Brad Beam\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","freebsd":">= 0.0.0","gentoo":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","solaris2":">= 0.0.0","oracle":">= 0.0.0","ubuntu":">= 0.0.0","windows":">= 0.0.0","mac_os_x":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"ntp":"Installs and configures ntp either as a server or client"},"source_url":"https://github.com/chef-cookbooks/ntp","issues_url":"https://github.com/chef-cookbooks/ntp/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/ntp/recipes/apparmor.rb b/cookbooks/ntp/recipes/apparmor.rb new file mode 100644 index 0000000..e5b19db --- /dev/null +++ b/cookbooks/ntp/recipes/apparmor.rb @@ -0,0 +1,30 @@ +# +# Cookbook:: ntp +# Recipe:: apparmor +# Author:: Scott Lampert () +# +# Copyright:: 2013-2017, Scott Lampert +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +service 'apparmor' do + action :nothing +end + +cookbook_file '/etc/apparmor.d/usr.sbin.ntpd' do + source 'usr.sbin.ntpd.apparmor' + owner 'root' + group 'root' + mode '0644' + notifies :restart, 'service[apparmor]' +end diff --git a/cookbooks/ntp/recipes/default.rb b/cookbooks/ntp/recipes/default.rb new file mode 100644 index 0000000..7b61f75 --- /dev/null +++ b/cookbooks/ntp/recipes/default.rb @@ -0,0 +1,129 @@ +# +# Cookbook:: ntp +# Recipe:: default +# Author:: Joshua Timberman () +# Author:: Tim Smith () +# +# Copyright:: 2009-2017, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +::Chef::Resource.send(:include, Opscode::Ntp::Helper) + +case node['platform_family'] +when 'windows' + include_recipe 'ntp::windows_client' +when 'mac_os_x' + include_recipe 'ntp::mac_os_x_client' + # On OS X we only support simple client config and nothing more + return 0 +else + + node['ntp']['packages'].each do |ntppkg| + package ntppkg + end + + package 'Remove ntpdate' do + package_name 'ntpdate' + action :remove + only_if { node['platform_family'] == 'debian' && node['platform_version'].to_i >= 16 } + end + + [node['ntp']['varlibdir'], node['ntp']['statsdir']].each do |ntpdir| + directory ntpdir do + owner node['ntp']['var_owner'] + group node['ntp']['var_group'] + mode '0755' + end + end + + cookbook_file node['ntp']['leapfile'] do + owner node['ntp']['conf_owner'] + group node['ntp']['conf_group'] + mode '0644' + source 'ntp.leapseconds' + notifies :restart, "service[#{node['ntp']['service']}]" + end + + include_recipe 'ntp::apparmor' if node['ntp']['apparmor_enabled'] +end + +if node['ntp']['servers'].empty? + node.default['ntp']['servers'] = [ + '0.pool.ntp.org', + '1.pool.ntp.org', + '2.pool.ntp.org', + '3.pool.ntp.org', + ] + Chef::Log.debug 'No NTP servers specified, using default ntp.org server pools' +end + +if node['ntp']['listen'].nil? && !node['ntp']['listen_network'].nil? + if node['ntp']['listen_network'] == 'primary' + node.normal['ntp']['listen'] = node['ipaddress'] + else + require 'ipaddr' + net = IPAddr.new(node['ntp']['listen_network']) + + node['network']['interfaces'].each do |_iface, addrs| + addrs['addresses'].each do |ip, params| + addr = IPAddr.new(ip) if params['family'].eql?('inet') || params['family'].eql?('inet6') + node.normal['ntp']['listen'] = addr if net.include?(addr) + end + end + end +end + +node.default['ntp']['tinker']['panic'] = 0 if node['virtualization'] && + node['virtualization']['role'] == 'guest' && + node['ntp']['disable_tinker_panic_on_virtualization_guest'] + +template node['ntp']['conffile'] do + source 'ntp.conf.erb' + owner node['ntp']['conf_owner'] + group node['ntp']['conf_group'] + mode '0644' + notifies :restart, "service[#{node['ntp']['service']}]" unless node['ntp']['conf_restart_immediate'] + notifies :restart, "service[#{node['ntp']['service']}]", :immediately if node['ntp']['conf_restart_immediate'] + variables( + lazy { { ntpd_supports_native_leapfiles: ntpd_supports_native_leapfiles } } + ) +end + +if node['ntp']['sync_clock'] && !platform_family?('windows') + execute "Stop #{node['ntp']['service']} in preparation for ntpdate" do + command node['platform_family'] == 'freebsd' ? '/usr/bin/true' : '/bin/true' + action :run + notifies :stop, "service[#{node['ntp']['service']}]", :immediately + end + + execute 'Force sync system clock with ntp server' do + command node['platform_family'] == 'freebsd' ? 'ntpd -q' : "ntpd -q -u #{node['ntp']['var_owner']}" + action :run + notifies :start, "service[#{node['ntp']['service']}]" + end +end + +execute 'Force sync hardware clock with system clock' do + command 'hwclock --systohc' + action :run + only_if { node['ntp']['sync_hw_clock'] && !(platform_family?('windows') || platform_family?('freebsd')) } +end + +service node['ntp']['service'] do + supports status: true, restart: true + action [:enable, :start] + timeout 120 if platform_family?('windows') + retries 3 + retry_delay 5 +end diff --git a/cookbooks/ntp/recipes/mac_os_x_client.rb b/cookbooks/ntp/recipes/mac_os_x_client.rb new file mode 100644 index 0000000..a08dc05 --- /dev/null +++ b/cookbooks/ntp/recipes/mac_os_x_client.rb @@ -0,0 +1,32 @@ +# +# Cookbook:: ntp +# Recipe:: mac_os_x_client +# Author:: Antek S. Baranski () +# +# Copyright:: 2016-2017, Roblox, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Do not continue if trying to run the Mac OS X recipe on non-OS X platform +return 'The ntp::mac_os_x_client recipe only supports Mac OS X' unless platform_family?('mac_os_x') + +# Mac OS X 10.11+ does not allow for many NTP settings +execute 'systemsetup -setnetworktimeserver' do + command "systemsetup -setnetworktimeserver #{node['ntp']['servers'][0]}" + not_if "systemsetup -getnetworktimeserver | grep -F #{node['ntp']['servers'][0]}" +end + +execute 'systemsetup -setusingnetworktime' do + command 'systemsetup -setusingnetworktime on' + not_if 'systemsetup -getusingnetworktime | grep On' +end diff --git a/cookbooks/ntp/recipes/windows_client.rb b/cookbooks/ntp/recipes/windows_client.rb new file mode 100644 index 0000000..98a7213 --- /dev/null +++ b/cookbooks/ntp/recipes/windows_client.rb @@ -0,0 +1,45 @@ +# +# Cookbook:: ntp +# Recipe:: windows_client +# Author:: Tim Smith () +# +# Copyright:: 2012-2017, Webtrends, Inc +# Copyright:: 2013-2017, Limelight Networks, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Do not continue if trying to run the Windows recipe on non-Windows platform +return 'The ntp::windows_client recipe only supports Windows' unless platform_family?('windows') + +directory 'C:/NTP/etc' do + inherits true + action :create + recursive true +end + +cookbook_file 'C:/NTP/ntp.ini' do + source 'ntp.ini' + inherits true + action :create +end + +unless File.exist?('C:/NTP/bin/ntpd.exe') + remote_file "#{Chef::Config[:file_cache_path]}/ntpd.exe" do + source node['ntp']['package_url'] + end + + execute 'ntpd_install' do + command "#{Chef::Config[:file_cache_path]}\\ntpd.exe /USEFILE=C:\\NTP\\ntp.ini" + returns [0, 2] + end +end diff --git a/cookbooks/ntp/templates/default/ntp.conf.erb b/cookbooks/ntp/templates/default/ntp.conf.erb new file mode 100644 index 0000000..23b6d2b --- /dev/null +++ b/cookbooks/ntp/templates/default/ntp.conf.erb @@ -0,0 +1,102 @@ +# Auto-generated by Chef. +# Local modifications will be overwritten. +# +<%# Windows OHAI does not support determining if a host is a guest %> +<% unless node['platform'] == 'windows' -%> +<%-%>tinker <%= node['ntp']['tinker'].flatten.join(' ') %> +<%-%>statsdir <%= node['ntp']['statsdir'] %> +<% if @ntpd_supports_native_leapfiles -%> +<%-%>leapfile <%= node['ntp']['leapfile'] %> +<% end -%> +<% end -%> +driftfile <%= node['ntp']['driftfile'] %> +<% if node['ntp']['logfile'] -%> +<%-%>logfile <%= node['ntp']['logfile'] %> +<% end -%> + +<%# Enable logs only if statistics option is defined %> +<% if node['ntp']['statistics'] -%> +<%-%>statistics loopstats peerstats clockstats +<%-%>filegen loopstats file loopstats type day enable +<%-%>filegen peerstats file peerstats type day enable +<%-%>filegen clockstats file clockstats type day enable +<% end -%> + +<%# If the ignore attribute is set on the node, then apply it %> +<% unless node['ntp']['ignore'].nil? -%> +<% Array(node['ntp']['ignore']).each do |ignore| -%> +interface ignore <%= ignore %> +<% end -%> +<% end -%> + +<%# If the listen attribute is set on the node, then apply it %> +<% unless node['ntp']['listen'].nil? -%> +<% Array(node['ntp']['listen']).each do |listen| -%> +interface listen <%= listen %> +<% end -%> +<%# The service must always listen on localhost %> +<% unless Array(node['ntp']['listen']).include? '127.0.0.1' -%> +interface listen 127.0.0.1 +<% end -%> +<% end -%> + +<% if node['ntp']['monitor'] -%> +enable monitor +<% else -%> +disable monitor +<% end -%> + +<%# If ntp.peers is not empty %> +<% unless node['ntp']['peers'].empty? -%> +<% node['ntp']['peers'].sort.each do |ntppeer| -%> +<%# Don't peer with ourself %> +<% if node['ipaddress'] != ntppeer && node['fqdn'] != ntppeer -%> +<% -%>peer <%= ntppeer %><% if key = node['ntp']['peer']['key'] -%> key <%= key %><% end -%><% if node['ntp']['peer']['use_iburst'] -%> iburst<% end -%><% if node['ntp']['peer']['use_burst'] -%> burst<% end -%> minpoll <%= node['ntp']['peer']['minpoll'] %> maxpoll <%= node['ntp']['peer']['maxpoll'] %> +<% -%>restrict <%= ntppeer %> nomodify +<% end -%> +<% end -%> +<% end -%> + +<%# Whether this is a client or server, we want upstream servers. %> +<%# We should guard the servers array against deep merge. %> +<%# This should keep authoritative local servers from being included twice. %> +<% ( node['ntp']['servers'] - node['ntp']['peers'] ).sort.each do |ntpserver| -%> +<%# Loop through defined servers, but don't try to upstream ourself %> +<% if node['ipaddress'] != ntpserver and node['fqdn'] != ntpserver -%> +<% -%>server <%= ntpserver %><% if node['ntp']['server']['use_iburst'] -%> iburst<% end -%><% if node['ntp']['server']['use_burst'] -%> burst<% end -%> minpoll <%= node['ntp']['server']['minpoll'] %> maxpoll <%= node['ntp']['server']['maxpoll'] %><% if node['ntp']['server']['prefer'] == ntpserver -%> prefer<% end -%> +<% -%>restrict <%= ntpserver %> nomodify notrap noquery +<% end -%> +<% end -%> + +restrict default <%= node['ntp']['restrict_default'] %> +restrict 127.0.0.1<%if node['ntp']['localhost']['noquery'] -%> noquery<% end -%> +restrict -6 default <%= node['ntp']['restrict_default'] %> +restrict -6 ::1<%if node['ntp']['localhost']['noquery'] -%> noquery<% end -%> + +<%# If this is a server with additional LAN restriction lines, put them here %> +<% unless node['ntp']['restrictions'].empty? -%> +<% node['ntp']['restrictions'].each do |restriction| -%> +<% -%>restrict <%= restriction %> +<% end -%> +<% end -%> + +<%# It is best practice to use a high stratum undisciplined clock, if you have a real CMOS clock %> +<%# Except cases where you have a low stratum server, or a virtualized system without a real CMOS clock %> +<% if node['ntp']['use_cmos'] -%> +<% -%>server 127.127.1.0 # local clock +<% -%>fudge 127.127.1.0 stratum 10 +<% end -%> + +<% if node['ntp']['orphan']['enabled'] -%> +tos orphan <%= node['ntp']['orphan']['stratum'] %> +<% end -%> + +<% if node['ntp']['keys'] -%> +keys <%= node['ntp']['keys'] %> +<% end -%> +<% if node['ntp']['trustedkey'] -%> +trustedkey <%= node['ntp']['trustedkey'] %> +<% end -%> +<% if node['ntp']['requestkey'] -%> +requestkey <%= node['ntp']['requestkey'] %> +<% end -%> diff --git a/cookbooks/openssl/CHANGELOG.md b/cookbooks/openssl/CHANGELOG.md index a65e2fe..d323a3b 100644 --- a/cookbooks/openssl/CHANGELOG.md +++ b/cookbooks/openssl/CHANGELOG.md @@ -2,6 +2,12 @@ This file is used to list changes made in each version of the openssl cookbook. +## 7.1.0 (2017-05-30) + +- Add supported platforms to the metdata +- Fix amazon support +- Remove class_eval usage and require Chef 12.7+ + ## 7.0.1 (2017-03-21) - Fix compatibility with Chef 12.5.1 diff --git a/cookbooks/openssl/README.md b/cookbooks/openssl/README.md index da19dbc..64c56ad 100644 --- a/cookbooks/openssl/README.md +++ b/cookbooks/openssl/README.md @@ -25,7 +25,7 @@ The `upgrade` recipe has been tested on the following platforms: ## Chef -- Chef 12.5+ +- Chef 12.7+ ## Cookbooks diff --git a/cookbooks/openssl/metadata.json b/cookbooks/openssl/metadata.json index 6e6d604..b8ba6b8 100644 --- a/cookbooks/openssl/metadata.json +++ b/cookbooks/openssl/metadata.json @@ -1 +1 @@ -{"name":"openssl","version":"7.0.1","description":"Provides a library with a method for generating secure random passwords.","long_description":"# OpenSSL Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/openssl.svg?branch=master)](http://travis-ci.org/chef-cookbooks/openssl) [![Cookbook Version](https://img.shields.io/cookbook/v/openssl.svg)](https://supermarket.chef.io/cookbooks/openssl)\n\nThis cookbook provides tools for working with the Ruby OpenSSL library. It includes:\n\n- A library method to generate secure random passwords in recipes, using the Ruby SecureRandom library.\n- A resource for generating RSA private keys.\n- A resource for generating x509 certificates.\n- A resource for generating dhparam.pem files.\n- An attribute-driven recipe for upgrading OpenSSL packages.\n\n## Platforms\n\nThe `random_password` mixin works on any platform with the Ruby SecureRandom module. This module is already included with Chef.\n\nThe `openssl_x509`, `openssl_rsa_key` and `openssl_dhparam` resources work on any platform with the OpenSSL Ruby bindings installed. These bindings are already included with Chef.\n\nThe `upgrade` recipe has been tested on the following platforms:\n\n- Debian / Ubuntu derivatives\n- RHEL and derivatives\n- Fedora\n- openSUSE / SUSE Linux Enterprises\n\n## Chef\n\n- Chef 12.5+\n\n## Cookbooks\n\n- none\n\n## Attributes\n\n- `node['openssl']['restart_services']` - An array of service resources that depend on the openssl packages. This array is empty by default, as Chef has no reasonable way to detect which applications or services are compiled against these packages. _Note_ Each service listed in this array should represent a \"`service`\" resource specified in the recipes of the node's run list.\n\n## Recipes\n\n### default\n\nAn empty placeholder recipe. Takes no action.\n\n### upgrade\n\nThe upgrade recipe iterates over the list of packages in the `node['openssl']['packages']` attribute, and manages them with the `:upgrade` action. Each package will send a `:restart` notification to service resources named in the `node['openssl']['restart_services']` attribute.\n\n#### Example Usage\n\nIn this example, assume the node is running the `stats_collector` daemon, which depends on the openssl library. Imagine that a new openssl vulnerability has been disclosed, and the operating system vendor has released an update to openssl to address this vulnerability. In order to protect the node, an administrator crafts this recipe:\n\n```ruby\nnode.default['openssl']['restart_services'] = ['stats_collector']\n\n# other recipe code here...\nservice 'stats_collector' do\n action [:enable, :start]\nend\n\ninclude_recipe 'openssl::upgrade'\n```\n\nWhen executed, this recipe will ensure that openssl is upgraded to the latest version, and that the `stats_collector` service is restarted to pick up the latest security fixes released in the openssl package.\n\n## Libraries & Resources\n\nThere are two mixins packaged with this cookbook.\n\n### random_password (`OpenSSLCookbook::RandomPassword`)\n\nThe `RandomPassword` mixin can be used to generate secure random passwords in Chef cookbooks, usually for assignment to a variable or an attribute. `random_password` uses Ruby's SecureRandom library and is customizable.\n\n#### Example Usage\n\n```ruby\nChef::Recipe.send(:include, OpenSSLCookbook::RandomPassword)\nnode.normal['my_secure_attribute'] = random_password\nnode.normal_unless['my_secure_attribute'] = random_password\nnode.normal['my_secure_attribute'] = random_password(length: 50)\nnode.normal['my_secure_attribute'] = random_password(length: 50, mode: :base64)\nnode.normal['my_secure_attribute'] = random_password(length: 50, mode: :base64, encoding: 'ASCII')\n```\n\nNote that node attributes are widely accessible. Storing unencrypted passwords in node attributes, as in this example, carries risk.\n\n### ~~secure_password (`Opscode::OpenSSL::Password`)~~\n\nThis library should be considered deprecated and will be removed in a future version. Please use `OpenSSLCookbook::RandomPassword` instead. The documentation is kept here for historical reasons.\n\n#### ~~Example Usage~~\n\n```ruby\n::Chef::Recipe.send(:include, Opscode::OpenSSL::Password)\nnode.normal_unless['my_password'] = secure_password\n```\n\n~~Note that node attributes are widely accessible. Storing unencrypted passwords in node attributes, as in this example, carries risk.~~\n\n### openssl_x509\n\nThis resource generates self-signed, PEM-formatted x509 certificates. If no existing key is specified, the resource will automatically generate a passwordless key with the certificate.\n\n#### Attributes\n\nName | Type | Description\n------------------ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n`common_name` | String (Required) | Value for the `CN` certificate field.\n`org` | String (Required) | Value for the `O` certificate field.\n`org_unit` | String (Required) | Value for the `OU` certificate field.\n`country` | String (Required) | Value for the `C` ssl field.\n`expire` | Fixnum (Optional) | Value representing the number of days from _now_ through which the issued certificate cert will remain valid. The certificate will expire after this period.\n`subject_alt_name` | Array (Optional) | Array of _Subject Alternative Name_ entries, in format `DNS:example.com` or `IP:1.2.3.4` _Default: empty_\n`key_file` | String (Optional) | The path to a certificate key file on the filesystem. If the `key_file` attribute is specified, the resource will attempt to source a key from this location. If no key file is found, the resource will generate a new key file at this location. If the `key_file` attribute is not specified, the resource will generate a key file in the same directory as the generated certificate, with the same name as the generated certificate.\n`key_pass` | String (Optional) | The passphrase for an existing key's passphrase\n`key_length` | Fixnum (Optional) | The desired Bit Length of the generated key. _Default: 2048_\n`owner` | String (optional) | The owner of all files created by the resource. _Default: \"root\"_\n`group` | String (optional) | The group of all files created by the resource. _Default: \"root\"_\n`mode` | String or Fixnum (Optional) | The permission mode of all files created by the resource. _Default: \"0400\"_\n\n#### Example Usage\n\nIn this example, an administrator wishes to create a self-signed x509 certificate for use with a web server. In order to create the certificate, the administrator crafts this recipe:\n\n```ruby\nopenssl_x509 '/etc/httpd/ssl/mycert.pem' do\n common_name 'www.f00bar.com'\n org 'Foo Bar'\n org_unit 'Lab'\n country 'US'\nend\n```\n\nWhen executed, this recipe will generate a key certificate at `/etc/httpd/ssl/mycert.key`. It will then use that key to generate a new certificate file at `/etc/httpd/ssl/mycert.pem`.\n\n### openssl_dhparam\n\nThis resource generates dhparam.pem files. If a valid dhparam.pem file is found at the specified location, no new file will be created. If a file is found at the specified location but it is not a valid dhparam file, it will be overwritten.\n\n#### Attributes\n\nName | Type | Description\n------------ | --------------------------- | ---------------------------------------------------------------------------\n`key_length` | Fixnum (Optional) | The desired Bit Length of the generated key. _Default: 2048_\n`generator` | Fixnum (Optional) | The desired Diffie-Hellmann generator. Can be _2_ or _5_.\n`owner` | String (optional) | The owner of all files created by the resource. _Default: \"root\"_\n`group` | String (optional) | The group of all files created by the resource. _Default: \"root\"_\n`mode` | String or Fixnum (Optional) | The permission mode of all files created by the resource. _Default: \"0644\"_\n\n#### Example Usage\n\nIn this example, an administrator wishes to create a dhparam.pem file for use with a web server. In order to create the .pem file, the administrator crafts this recipe:\n\n```ruby\nopenssl_dhparam '/etc/httpd/ssl/dhparam.pem' do\n key_length 2048\n generator 2\nend\n```\n\nWhen executed, this recipe will generate a dhparam file at `/etc/httpd/ssl/dhparam.pem`.\n\n### openssl_rsa_key\n\nThis resource generates rsa key files. If a valid rsa key file can be opened at the specified location, no new file will be created. If the RSA key file cannot be opened, either because it does not exist or because the password to the RSA key file does not match the password in the recipe, it will be overwritten.\n\n#### Attributes\n\nName | Type | Description\n------------ | --------------------------- | ---------------------------------------------------------------------------\n`key_length` | Fixnum (Optional) | The desired Bit Length of the generated key. _Default: 2048_\n`key_pass` | String (Optional) | The desired passphrase for the key.\n`owner` | String (optional) | The owner of all files created by the resource. _Default: \"root\"_\n`group` | String (optional) | The group of all files created by the resource. _Default: \"root\"_\n`mode` | String or Fixnum (Optional) | The permission mode of all files created by the resource. _Default: \"0644\"_\n\n#### Example Usage\n\nIn this example, an administrator wishes to create a new RSA private key file in order to generate other certificates and public keys. In order to create the key file, the administrator crafts this recipe:\n\n```ruby\nopenssl_rsa_key '/etc/httpd/ssl/server.key' do\n key_length 2048\nend\n```\n\nWhen executed, this recipe will generate a passwordless RSA key file at `/etc/httpd/ssl/server.key`.\n\n## License and Author\n\nAuthor:: Jesse Nelson ([spheromak@gmail.com](mailto:spheromak@gmail.com))
\nAuthor:: Seth Vargo ([sethvargo@gmail.com](mailto:sethvargo@gmail.com))
\nAuthor:: Charles Johnson ([charles@chef.io](mailto:charles@chef.io))
\nAuthor:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))\n\n```text\nCopyright:: 2009-2016, Chef Software, Inc \n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"openssl":"Empty, this cookbook provides a library, see README.md","upgrade":"Upgrade OpenSSL library and restart dependent services"},"source_url":"https://github.com/chef-cookbooks/openssl","issues_url":"https://github.com/chef-cookbooks/openssl/issues","chef_version":">= 12.5","ohai_version":{}} \ No newline at end of file +{"name":"openssl","version":"7.1.0","description":"Provides a library with a method for generating secure random passwords.","long_description":"# OpenSSL Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/openssl.svg?branch=master)](http://travis-ci.org/chef-cookbooks/openssl) [![Cookbook Version](https://img.shields.io/cookbook/v/openssl.svg)](https://supermarket.chef.io/cookbooks/openssl)\n\nThis cookbook provides tools for working with the Ruby OpenSSL library. It includes:\n\n- A library method to generate secure random passwords in recipes, using the Ruby SecureRandom library.\n- A resource for generating RSA private keys.\n- A resource for generating x509 certificates.\n- A resource for generating dhparam.pem files.\n- An attribute-driven recipe for upgrading OpenSSL packages.\n\n## Platforms\n\nThe `random_password` mixin works on any platform with the Ruby SecureRandom module. This module is already included with Chef.\n\nThe `openssl_x509`, `openssl_rsa_key` and `openssl_dhparam` resources work on any platform with the OpenSSL Ruby bindings installed. These bindings are already included with Chef.\n\nThe `upgrade` recipe has been tested on the following platforms:\n\n- Debian / Ubuntu derivatives\n- RHEL and derivatives\n- Fedora\n- openSUSE / SUSE Linux Enterprises\n\n## Chef\n\n- Chef 12.7+\n\n## Cookbooks\n\n- none\n\n## Attributes\n\n- `node['openssl']['restart_services']` - An array of service resources that depend on the openssl packages. This array is empty by default, as Chef has no reasonable way to detect which applications or services are compiled against these packages. _Note_ Each service listed in this array should represent a \"`service`\" resource specified in the recipes of the node's run list.\n\n## Recipes\n\n### default\n\nAn empty placeholder recipe. Takes no action.\n\n### upgrade\n\nThe upgrade recipe iterates over the list of packages in the `node['openssl']['packages']` attribute, and manages them with the `:upgrade` action. Each package will send a `:restart` notification to service resources named in the `node['openssl']['restart_services']` attribute.\n\n#### Example Usage\n\nIn this example, assume the node is running the `stats_collector` daemon, which depends on the openssl library. Imagine that a new openssl vulnerability has been disclosed, and the operating system vendor has released an update to openssl to address this vulnerability. In order to protect the node, an administrator crafts this recipe:\n\n```ruby\nnode.default['openssl']['restart_services'] = ['stats_collector']\n\n# other recipe code here...\nservice 'stats_collector' do\n action [:enable, :start]\nend\n\ninclude_recipe 'openssl::upgrade'\n```\n\nWhen executed, this recipe will ensure that openssl is upgraded to the latest version, and that the `stats_collector` service is restarted to pick up the latest security fixes released in the openssl package.\n\n## Libraries & Resources\n\nThere are two mixins packaged with this cookbook.\n\n### random_password (`OpenSSLCookbook::RandomPassword`)\n\nThe `RandomPassword` mixin can be used to generate secure random passwords in Chef cookbooks, usually for assignment to a variable or an attribute. `random_password` uses Ruby's SecureRandom library and is customizable.\n\n#### Example Usage\n\n```ruby\nChef::Recipe.send(:include, OpenSSLCookbook::RandomPassword)\nnode.normal['my_secure_attribute'] = random_password\nnode.normal_unless['my_secure_attribute'] = random_password\nnode.normal['my_secure_attribute'] = random_password(length: 50)\nnode.normal['my_secure_attribute'] = random_password(length: 50, mode: :base64)\nnode.normal['my_secure_attribute'] = random_password(length: 50, mode: :base64, encoding: 'ASCII')\n```\n\nNote that node attributes are widely accessible. Storing unencrypted passwords in node attributes, as in this example, carries risk.\n\n### ~~secure_password (`Opscode::OpenSSL::Password`)~~\n\nThis library should be considered deprecated and will be removed in a future version. Please use `OpenSSLCookbook::RandomPassword` instead. The documentation is kept here for historical reasons.\n\n#### ~~Example Usage~~\n\n```ruby\n::Chef::Recipe.send(:include, Opscode::OpenSSL::Password)\nnode.normal_unless['my_password'] = secure_password\n```\n\n~~Note that node attributes are widely accessible. Storing unencrypted passwords in node attributes, as in this example, carries risk.~~\n\n### openssl_x509\n\nThis resource generates self-signed, PEM-formatted x509 certificates. If no existing key is specified, the resource will automatically generate a passwordless key with the certificate.\n\n#### Attributes\n\nName | Type | Description\n------------------ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n`common_name` | String (Required) | Value for the `CN` certificate field.\n`org` | String (Required) | Value for the `O` certificate field.\n`org_unit` | String (Required) | Value for the `OU` certificate field.\n`country` | String (Required) | Value for the `C` ssl field.\n`expire` | Fixnum (Optional) | Value representing the number of days from _now_ through which the issued certificate cert will remain valid. The certificate will expire after this period.\n`subject_alt_name` | Array (Optional) | Array of _Subject Alternative Name_ entries, in format `DNS:example.com` or `IP:1.2.3.4` _Default: empty_\n`key_file` | String (Optional) | The path to a certificate key file on the filesystem. If the `key_file` attribute is specified, the resource will attempt to source a key from this location. If no key file is found, the resource will generate a new key file at this location. If the `key_file` attribute is not specified, the resource will generate a key file in the same directory as the generated certificate, with the same name as the generated certificate.\n`key_pass` | String (Optional) | The passphrase for an existing key's passphrase\n`key_length` | Fixnum (Optional) | The desired Bit Length of the generated key. _Default: 2048_\n`owner` | String (optional) | The owner of all files created by the resource. _Default: \"root\"_\n`group` | String (optional) | The group of all files created by the resource. _Default: \"root\"_\n`mode` | String or Fixnum (Optional) | The permission mode of all files created by the resource. _Default: \"0400\"_\n\n#### Example Usage\n\nIn this example, an administrator wishes to create a self-signed x509 certificate for use with a web server. In order to create the certificate, the administrator crafts this recipe:\n\n```ruby\nopenssl_x509 '/etc/httpd/ssl/mycert.pem' do\n common_name 'www.f00bar.com'\n org 'Foo Bar'\n org_unit 'Lab'\n country 'US'\nend\n```\n\nWhen executed, this recipe will generate a key certificate at `/etc/httpd/ssl/mycert.key`. It will then use that key to generate a new certificate file at `/etc/httpd/ssl/mycert.pem`.\n\n### openssl_dhparam\n\nThis resource generates dhparam.pem files. If a valid dhparam.pem file is found at the specified location, no new file will be created. If a file is found at the specified location but it is not a valid dhparam file, it will be overwritten.\n\n#### Attributes\n\nName | Type | Description\n------------ | --------------------------- | ---------------------------------------------------------------------------\n`key_length` | Fixnum (Optional) | The desired Bit Length of the generated key. _Default: 2048_\n`generator` | Fixnum (Optional) | The desired Diffie-Hellmann generator. Can be _2_ or _5_.\n`owner` | String (optional) | The owner of all files created by the resource. _Default: \"root\"_\n`group` | String (optional) | The group of all files created by the resource. _Default: \"root\"_\n`mode` | String or Fixnum (Optional) | The permission mode of all files created by the resource. _Default: \"0644\"_\n\n#### Example Usage\n\nIn this example, an administrator wishes to create a dhparam.pem file for use with a web server. In order to create the .pem file, the administrator crafts this recipe:\n\n```ruby\nopenssl_dhparam '/etc/httpd/ssl/dhparam.pem' do\n key_length 2048\n generator 2\nend\n```\n\nWhen executed, this recipe will generate a dhparam file at `/etc/httpd/ssl/dhparam.pem`.\n\n### openssl_rsa_key\n\nThis resource generates rsa key files. If a valid rsa key file can be opened at the specified location, no new file will be created. If the RSA key file cannot be opened, either because it does not exist or because the password to the RSA key file does not match the password in the recipe, it will be overwritten.\n\n#### Attributes\n\nName | Type | Description\n------------ | --------------------------- | ---------------------------------------------------------------------------\n`key_length` | Fixnum (Optional) | The desired Bit Length of the generated key. _Default: 2048_\n`key_pass` | String (Optional) | The desired passphrase for the key.\n`owner` | String (optional) | The owner of all files created by the resource. _Default: \"root\"_\n`group` | String (optional) | The group of all files created by the resource. _Default: \"root\"_\n`mode` | String or Fixnum (Optional) | The permission mode of all files created by the resource. _Default: \"0644\"_\n\n#### Example Usage\n\nIn this example, an administrator wishes to create a new RSA private key file in order to generate other certificates and public keys. In order to create the key file, the administrator crafts this recipe:\n\n```ruby\nopenssl_rsa_key '/etc/httpd/ssl/server.key' do\n key_length 2048\nend\n```\n\nWhen executed, this recipe will generate a passwordless RSA key file at `/etc/httpd/ssl/server.key`.\n\n## License and Author\n\nAuthor:: Jesse Nelson ([spheromak@gmail.com](mailto:spheromak@gmail.com))
\nAuthor:: Seth Vargo ([sethvargo@gmail.com](mailto:sethvargo@gmail.com))
\nAuthor:: Charles Johnson ([charles@chef.io](mailto:charles@chef.io))
\nAuthor:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))\n\n```text\nCopyright:: 2009-2016, Chef Software, Inc \n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","suse":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","scientific":">= 0.0.0","oracle":">= 0.0.0","amazon":">= 0.0.0","zlinux":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"openssl":"Empty, this cookbook provides a library, see README.md","upgrade":"Upgrade OpenSSL library and restart dependent services"},"source_url":"https://github.com/chef-cookbooks/openssl","issues_url":"https://github.com/chef-cookbooks/openssl/issues","chef_version":[[">= 12.7"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/openssl/recipes/upgrade.rb b/cookbooks/openssl/recipes/upgrade.rb index d9d6f4a..7577d79 100644 --- a/cookbooks/openssl/recipes/upgrade.rb +++ b/cookbooks/openssl/recipes/upgrade.rb @@ -20,7 +20,7 @@ case node['platform_family'] when 'debian', 'ubuntu' packages = %w(libssl1.0.0 openssl) -when 'rhel', 'fedora', 'suse' +when 'rhel', 'fedora', 'suse', 'amazon' packages = %w(openssl) else packages = [] diff --git a/cookbooks/openssl/resources/x509.rb b/cookbooks/openssl/resources/x509.rb index 2929cbf..9801835 100644 --- a/cookbooks/openssl/resources/x509.rb +++ b/cookbooks/openssl/resources/x509.rb @@ -42,7 +42,7 @@ action :create do end end -action_class.class_eval do +action_class do def generate_key_file unless new_resource.key_file path, file = ::File.split(new_resource.name) diff --git a/cookbooks/php-fpm/.kitchen.yml b/cookbooks/php-fpm/.kitchen.yml deleted file mode 100644 index 07393c6..0000000 --- a/cookbooks/php-fpm/.kitchen.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_solo - -platforms: - - name: ubuntu-12.04 - - name: centos-6.4 - - name: fedora-21 - -suites: - - name: default - run_list: - - recipe[php-fpm::default] - attributes: - php-fpm: - pools: - - name: web - listen: '127.0.0.1:9081' diff --git a/cookbooks/php-fpm/.ruby-version b/cookbooks/php-fpm/.ruby-version deleted file mode 100644 index 0ca8caf..0000000 --- a/cookbooks/php-fpm/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -1.9.3-p327 diff --git a/cookbooks/php-fpm/Berksfile b/cookbooks/php-fpm/Berksfile deleted file mode 100644 index 0ac9b78..0000000 --- a/cookbooks/php-fpm/Berksfile +++ /dev/null @@ -1,3 +0,0 @@ -source "https://supermarket.getchef.com" - -metadata diff --git a/cookbooks/php-fpm/Gemfile b/cookbooks/php-fpm/Gemfile deleted file mode 100644 index eca2238..0000000 --- a/cookbooks/php-fpm/Gemfile +++ /dev/null @@ -1,20 +0,0 @@ -source 'https://rubygems.org' - -gem 'berkshelf' - -# Uncomment these lines if you want to live on the Edge: -# -# group :development do -# gem "berkshelf", github: "berkshelf/berkshelf" -# gem "vagrant", github: "mitchellh/vagrant", tag: "v1.6.3" -# end -# -# group :plugins do -# gem "vagrant-berkshelf", github: "berkshelf/vagrant-berkshelf" -# gem "vagrant-omnibus", github: "schisamo/vagrant-omnibus" -# end - -gem 'test-kitchen' -gem 'kitchen-vagrant' -gem 'stove' -gem 'serverspec' diff --git a/cookbooks/php-fpm/Gemfile.lock b/cookbooks/php-fpm/Gemfile.lock deleted file mode 100644 index cc6cb33..0000000 --- a/cookbooks/php-fpm/Gemfile.lock +++ /dev/null @@ -1,179 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (3.2.19) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) - addressable (2.3.6) - akami (1.2.2) - gyoku (>= 0.4.0) - nokogiri - berkshelf (2.0.18) - activesupport (~> 3.2.0) - addressable (~> 2.3.4) - buff-shell_out (~> 0.1) - chozo (>= 0.6.1) - faraday (~> 0.8.5) - hashie (~> 2.0) - minitar (~> 0.5.4) - rbzip2 (~> 0.2.0) - retryable (~> 1.3.3) - ridley (~> 1.7.0) - solve (~> 0.8.2) - thor (~> 0.18.0) - buff-config (0.4.0) - buff-extensions (~> 0.3) - varia_model (~> 0.1) - buff-extensions (0.5.0) - buff-ignore (1.1.1) - buff-ruby_engine (0.1.0) - buff-shell_out (0.2.0) - buff-ruby_engine (~> 0.1.0) - builder (3.2.2) - celluloid (0.16.0) - timers (~> 4.0.0) - celluloid-io (0.16.1) - celluloid (>= 0.16.0) - nio4r (>= 1.0.0) - chef-api (0.5.0) - logify (~> 0.1) - mime-types - chozo (0.6.1) - activesupport (>= 3.2.0) - hashie (>= 2.0.2) - multi_json (>= 1.3.0) - diff-lcs (1.2.5) - erubis (2.7.0) - faraday (0.8.9) - multipart-post (~> 1.2.0) - ffi (1.9.6) - gssapi (1.0.3) - ffi (>= 1.0.1) - gyoku (1.2.2) - builder (>= 2.1.2) - hashie (2.1.2) - hitimes (1.2.2) - httpclient (2.5.1) - httpi (0.9.7) - rack - i18n (0.6.11) - json (1.8.1) - kitchen-vagrant (0.15.0) - test-kitchen (~> 1.0) - little-plugger (1.1.3) - logging (1.8.2) - little-plugger (>= 1.1.3) - multi_json (>= 1.8.4) - logify (0.2.0) - mime-types (2.4.2) - mini_portile (0.6.0) - minitar (0.5.4) - mixlib-authentication (1.3.0) - mixlib-log - mixlib-log (1.6.0) - mixlib-shellout (1.6.1) - multi_json (1.10.1) - multipart-post (1.2.0) - net-http-persistent (2.9.4) - net-scp (1.2.1) - net-ssh (>= 2.6.5) - net-ssh (2.9.1) - nio4r (1.0.1) - nokogiri (1.6.3.1) - mini_portile (= 0.6.0) - nori (1.1.5) - rack (1.5.2) - rbzip2 (0.2.0) - retryable (1.3.6) - ridley (1.7.1) - addressable - buff-config (~> 0.2) - buff-extensions (~> 0.3) - buff-ignore (~> 1.1) - buff-shell_out (~> 0.1) - celluloid (~> 0.15) - celluloid-io (~> 0.15) - erubis - faraday (>= 0.8.4) - hashie (>= 2.0.2) - json (>= 1.7.7) - mixlib-authentication (>= 1.3.0) - net-http-persistent (>= 2.8) - net-ssh - retryable - solve (>= 0.4.4) - varia_model (~> 0.1) - winrm (~> 1.1.0) - rspec (3.1.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) - rspec-core (3.1.7) - rspec-support (~> 3.1.0) - rspec-expectations (3.1.2) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.1.0) - rspec-its (1.0.1) - rspec-core (>= 2.99.0.beta1) - rspec-expectations (>= 2.99.0.beta1) - rspec-mocks (3.1.3) - rspec-support (~> 3.1.0) - rspec-support (3.1.2) - rubyntlm (0.1.1) - safe_yaml (1.0.4) - savon (0.9.5) - akami (~> 1.0) - builder (>= 2.1.2) - gyoku (>= 0.4.0) - httpi (~> 0.9) - nokogiri (>= 1.4.0) - nori (~> 1.0) - wasabi (~> 1.0) - serverspec (2.3.1) - multi_json - rspec (~> 3.0) - rspec-its - specinfra (~> 2.3) - solve (0.8.2) - specinfra (2.3.0) - net-scp - net-ssh - stove (3.2.3) - chef-api (~> 0.5) - logify (~> 0.2) - test-kitchen (1.2.1) - mixlib-shellout (~> 1.2) - net-scp (~> 1.1) - net-ssh (~> 2.7) - safe_yaml (~> 1.0) - thor (~> 0.18) - thor (0.18.1) - timers (4.0.1) - hitimes - uuidtools (2.1.5) - varia_model (0.3.2) - buff-extensions (~> 0.2) - hashie (>= 2.0.2) - wasabi (1.0.0) - nokogiri (>= 1.4.0) - winrm (1.1.3) - gssapi (~> 1.0.0) - httpclient (~> 2.2, >= 2.2.0.2) - logging (~> 1.6, >= 1.6.1) - nokogiri (~> 1.5) - rubyntlm (~> 0.1.1) - savon (= 0.9.5) - uuidtools (~> 2.1.2) - -PLATFORMS - ruby - -DEPENDENCIES - berkshelf - kitchen-vagrant - serverspec - stove - test-kitchen - -BUNDLED WITH - 1.10.3 diff --git a/cookbooks/php-fpm/README.md b/cookbooks/php-fpm/README.md index 4a11ecc..0bd779d 100644 --- a/cookbooks/php-fpm/README.md +++ b/cookbooks/php-fpm/README.md @@ -1,3 +1,5 @@ +[![Build Status](https://travis-ci.org/yevgenko/cookbook-php-fpm.svg?branch=master)](https://travis-ci.org/yevgenko/cookbook-php-fpm) + Description =========== @@ -77,6 +79,57 @@ php_fpm_pool "www" do end ``` +Development +=========== + +### Requirements + +* [Docker](https://www.docker.com/) + +### Setup + +To get all dependencies: + +``` +bundle install +``` + +### Test + +To see available platforms: + +``` +bundle exec rake -T +``` + +To test particular platform: + +``` +bundle exec rake kitchen:default-ubuntu-1604 +``` + +To test all platforms: + +``` +bundle exec rake kitchen:all +``` + +### Publishing (maintainers only!) + +Bump version in metadata.rb, commit and push to master! + +``` +bundle exec rake publish +``` + +as a result new tag will be created and pushed to github as well as new version +will be published on https://supermarket.chef.io + +Contributing +=========== + +Please do not bump version when proposing a change, no other rules ;) + License and Author ================== diff --git a/cookbooks/php-fpm/Rakefile b/cookbooks/php-fpm/Rakefile deleted file mode 100644 index c13c98f..0000000 --- a/cookbooks/php-fpm/Rakefile +++ /dev/null @@ -1,13 +0,0 @@ -begin - require 'kitchen/rake_tasks' - Kitchen::RakeTasks.new -rescue LoadError - puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] -end - -begin - require 'stove/rake_task' - Stove::RakeTask.new -rescue LoadErro - pust ">>>>> Stove gem not loaded, omitting tasks" unless ENV['CI'] -end diff --git a/cookbooks/php-fpm/Thorfile b/cookbooks/php-fpm/Thorfile deleted file mode 100644 index b23ee16..0000000 --- a/cookbooks/php-fpm/Thorfile +++ /dev/null @@ -1,12 +0,0 @@ -# encoding: utf-8 - -require 'bundler' -require 'bundler/setup' -require 'berkshelf/thor' - -begin - require 'kitchen/thor_tasks' - Kitchen::ThorTasks.new -rescue LoadError - puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] -end diff --git a/cookbooks/php-fpm/Vagrantfile b/cookbooks/php-fpm/Vagrantfile deleted file mode 100644 index 370049d..0000000 --- a/cookbooks/php-fpm/Vagrantfile +++ /dev/null @@ -1,90 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.require_version ">= 1.5.0" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - # All Vagrant configuration is done here. The most common configuration - # options are documented and commented below. For a complete reference, - # please see the online documentation at vagrantup.com. - - config.vm.hostname = "php-fpm-berkshelf" - - # Set the version of chef to install using the vagrant-omnibus plugin - config.omnibus.chef_version = :latest - - # Every Vagrant virtual environment requires a box to build off of. - # If this value is a shorthand to a box in Vagrant Cloud then - # config.vm.box_url doesn't need to be specified. - # config.vm.box = "chef/ubuntu-14.04" - case ENV['VMBOX'] - when 'centos65' - config.vm.box = "opscode-centos-6.5" - config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box" - else - config.vm.box = "opscode-ubuntu-12.04" - config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-12.04_chef-provisionerless.box" - end - - # The url from where the 'config.vm.box' box will be fetched if it - # is not a Vagrant Cloud box and if it doesn't already exist on the - # user's system. - # config.vm.box_url = "https://vagrantcloud.com/chef/ubuntu-14.04/version/1/provider/virtualbox.box" - - # Assign this VM to a host-only network IP, allowing you to access it - # via the IP. Host-only networks can talk to the host machine as well as - # any other machines on the same network, but cannot be accessed (through this - # network interface) by any external networks. - # config.vm.network :private_network, type: "dhcp" - config.vm.network :private_network, ip: "33.33.33.10" - - # Create a forwarded port mapping which allows access to a specific port - # within the machine from a port on the host machine. In the example below, - # accessing "localhost:8080" will access port 80 on the guest machine. - - # Share an additional folder to the guest VM. The first argument is - # the path on the host to the actual folder. The second argument is - # the path on the guest to mount the folder. And the optional third - # argument is a set of non-required options. - # config.vm.synced_folder "../data", "/vagrant_data" - - # Provider-specific configuration so you can fine-tune various - # backing providers for Vagrant. These expose provider-specific options. - # Example for VirtualBox: - # - # config.vm.provider :virtualbox do |vb| - # # Don't boot with headless mode - # vb.gui = true - # - # # Use VBoxManage to customize the VM. For example to change memory: - # vb.customize ["modifyvm", :id, "--memory", "1024"] - # end - # - # View the documentation for the provider you're using for more - # information on available options. - - # The path to the Berksfile to use with Vagrant Berkshelf - # config.berkshelf.berksfile_path = "./Berksfile" - - # Enabling the Berkshelf plugin. To enable this globally, add this configuration - # option to your ~/.vagrant.d/Vagrantfile file - config.berkshelf.enabled = true - - # An array of symbols representing groups of cookbook described in the Vagrantfile - # to exclusively install and copy to Vagrant's shelf. - # config.berkshelf.only = [] - - # An array of symbols representing groups of cookbook described in the Vagrantfile - # to skip installing and copying to Vagrant's shelf. - # config.berkshelf.except = [] - - config.vm.provision :chef_solo do |chef| - chef.run_list = [ - "recipe[apt]", - "recipe[php-fpm::default]" - ] - end -end diff --git a/cookbooks/php-fpm/attributes/default.rb b/cookbooks/php-fpm/attributes/default.rb index c5ad1c4..2f5d088 100644 --- a/cookbooks/php-fpm/attributes/default.rb +++ b/cookbooks/php-fpm/attributes/default.rb @@ -10,15 +10,22 @@ when "rhel", "fedora" else user = "www-data" group = "www-data" - conf_dir = "/etc/php5/fpm/conf.d" - pool_conf_dir = "/etc/php5/fpm/pool.d" - if node.platform == "ubuntu" and node.platform_version.to_f <= 10.04 - conf_file = "/etc/php5/fpm/php5-fpm.conf" + if platform?('ubuntu') and node['platform_version'].to_f >= 16.04 + php_conf_dir = "/etc/php/7.0" + php_fpm_name = "php7.0-fpm" else - conf_file = "/etc/php5/fpm/php-fpm.conf" + php_conf_dir = "/etc/php5" + php_fpm_name = "php5-fpm" end - error_log = "/var/log/php5-fpm.log" - pid ="/var/run/php5-fpm.pid" + conf_dir = "#{php_conf_dir}/fpm/conf.d" + pool_conf_dir = "#{php_conf_dir}/fpm/pool.d" + if node['platform'] == "ubuntu" and node['platform_version'].to_f <= 10.04 + conf_file = "#{php_conf_dir}/fpm/php5-fpm.conf" + else + conf_file = "#{php_conf_dir}/fpm/php-fpm.conf" + end + error_log = "/var/log/#{php_fpm_name}.log" + pid = "/var/run/#{php_fpm_name}.pid" end default['php-fpm']['user'] = user @@ -28,11 +35,23 @@ default['php-fpm']['pool_conf_dir'] = pool_conf_dir default['php-fpm']['conf_file'] = conf_file default['php-fpm']['pid'] = pid default['php-fpm']['log_dir'] = '/var/log/php-fpm' -default['php-fpm']['error_log'] = error_log +default['php-fpm']['error_log'] = error_log default['php-fpm']['log_level'] = "notice" default['php-fpm']['emergency_restart_threshold'] = 0 default['php-fpm']['emergency_restart_interval'] = 0 default['php-fpm']['process_control_timeout'] = 0 +default['php-fpm']['process_manager'] = 'ondemand' +default['php-fpm']['max_children'] = 50 +default['php-fpm']['start_servers'] = 5 +default['php-fpm']['min_spare_servers'] = 5 +default['php-fpm']['max_spare_servers'] = 35 +default['php-fpm']['max_requests'] = 0 +default['php-fpm']['request_terminate_timeout'] = 0 +default['php-fpm']['catch_workers_output'] = 'no' +default['php-fpm']['security_limit_extensions'] = '.php' +default['php-fpm']['listen_mode'] = '0660' +default['php-fpm']['listen'] = "/var/run/php-fpm-%{pool_name}.sock" + default['php-fpm']['pools'] = { "www" => { :enable => true diff --git a/cookbooks/php-fpm/definitions/php_fpm_pool.rb b/cookbooks/php-fpm/definitions/php_fpm_pool.rb index ae7c2b6..edd1b0e 100644 --- a/cookbooks/php-fpm/definitions/php_fpm_pool.rb +++ b/cookbooks/php-fpm/definitions/php_fpm_pool.rb @@ -33,24 +33,26 @@ define :php_fpm_pool, :template => "pool.conf.erb", :enable => true do cookbook params[:cookbook] || "php-fpm" variables( :pool_name => pool_name, - :listen => params[:listen], + :listen => params[:listen] || node['php-fpm']['listen'].gsub(%r[%{pool_name}], pool_name), :listen_owner => params[:listen_owner] || node['php-fpm']['listen_owner'] || node['php-fpm']['user'], :listen_group => params[:listen_group] || node['php-fpm']['listen_group'] || node['php-fpm']['group'], :listen_mode => params[:listen_mode] || node['php-fpm']['listen_mode'], :allowed_clients => params[:allowed_clients], - :user => params[:user], - :group => params[:group], - :process_manager => params[:process_manager], - :max_children => params[:max_children], - :start_servers => params[:start_servers], - :min_spare_servers => params[:min_spare_servers], - :max_spare_servers => params[:max_spare_servers], - :max_requests => params[:max_requests], - :catch_workers_output => params[:catch_workers_output], + :user => params[:user] || node['php-fpm']['user'], + :group => params[:group] || node['php-fpm']['group'], + :process_manager => params[:process_manager] || node['php-fpm']['process_manager'], + :max_children => params[:max_children] || node['php-fpm']['max_children'], + :start_servers => params[:start_servers] || node['php-fpm']['start_servers'], + :min_spare_servers => params[:min_spare_servers] || node['php-fpm']['min_spare_servers'], + :max_spare_servers => params[:max_spare_servers] || node['php-fpm']['max_spare_servers'], + :max_requests => params[:max_requests] || node['php-fpm']['max_requests'], + :catch_workers_output => params[:catch_workers_output] || node['php-fpm']['catch_workers_output'], :security_limit_extensions => params[:security_limit_extensions] || node['php-fpm']['security_limit_extensions'], :access_log => params[:access_log] || false, + :slowlog => params[:slowlog] || false, + :request_slowlog_timeout => params[:request_slowlog_timeout] || false, :php_options => params[:php_options] || {}, - :request_terminate_timeout => params[:request_terminate_timeout], + :request_terminate_timeout => params[:request_terminate_timeout] || node['php-fpm']['request_terminate_timeout'], :params => params ) notifies :restart, "service[php-fpm]" diff --git a/cookbooks/php-fpm/metadata.json b/cookbooks/php-fpm/metadata.json new file mode 100644 index 0000000..bd15377 --- /dev/null +++ b/cookbooks/php-fpm/metadata.json @@ -0,0 +1,37 @@ +{ + "name": "php-fpm", + "version": "0.7.9", + "description": "Installs/Configures php-fpm", + "long_description": "[![Build Status](https://travis-ci.org/yevgenko/cookbook-php-fpm.svg?branch=master)](https://travis-ci.org/yevgenko/cookbook-php-fpm)\n\nDescription\n===========\n\nInstalls and configures PHP-FPM (FastCGI Process Manager), an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites. It's like the `unicorn` of the PHP world dawg.\n\nRequirements\n============\n\nPlatform\n--------\n\n* Debian, Ubuntu\n* CentOS, Red Hat, Fedora\n* Amazon Linux\n\nCookbooks\n---------\n\n* apt (leverages apt_repository LWRP)\n* yum (leverages yum_repository LWRP)\n\nThe `apt_repository` and `yum_repository` LWRPs are used from these cookbooks to create the proper repository entries so the php-fpm package downloaded and installed.\n\nDescription\n==========\n\nCreates a PHP-FPM configuration file at the path specified. Meant to be deployed with a service init scheme/supervisor such as runit. Please see the `application::php-fpm` recipe for a complete working example. In depth information about PHP-FPM's configuration values can be [found in the PHP-FPM documentation](http://php.net/manual/en/install.fpm.configuration.php).\n\nUsage\n=====\nSimply include the recipe where you want PHP-FPM installed. Default pool __www__ will be created. To disable pool creation set default['php-fpm']['pools'] to false.\n\nTo customize settings and pools you can override default attributes.\n\n### Usage in roles:\n```ruby\nname \"php-fpm\"\ndescription \"php fpm role\"\nrun_list \"recipe[php-fpm]\"\noverride_attributes \"php-fpm\" => {\n\t\"pools\" => {\n\t\t\"default\" => {\n\t\t\t:enable => true\n\t\t},\n\t\t\"www\" => {\n\t\t\t:enable => \"true\",\n\t\t\t:cookbook => \"another-cookbook\",\n\t\t\t:process_manager => \"dynamic\",\n\t\t\t:max_requests => 5000,\n\t\t\t:php_options => { 'php_admin_flag[log_errors]' => 'on', 'php_admin_value[memory_limit]' => '32M' }\n\t\t}\n\t}\n}\n```\n\nCreating pools in recipes\n=========================\n### Create PHP-FPM pool named 'www' with default settings:\n```ruby\nphp_fpm_pool \"www\"\n```\n\n### Create PHP-FPM pool named 'www' with custom settings:\n```ruby\nphp_fpm_pool \"www\" do\n cookbook \"another-cookbook\" # get template from another cookbook\n process_manager \"dynamic\"\n max_requests 5000\n php_options 'php_admin_flag[log_errors]' => 'on', 'php_admin_value[memory_limit]' => '32M'\nend\n```\n\n### Delete PHP-FPM pool named 'www':\n```ruby\nphp_fpm_pool \"www\" do\n enable false\nend\n```\n\nDevelopment\n===========\n\n### Requirements\n\n* [Docker](https://www.docker.com/)\n\n### Setup\n\nTo get all dependencies:\n\n```\nbundle install\n```\n\n### Test\n\nTo see available platforms:\n\n```\nbundle exec rake -T\n```\n\nTo test particular platform:\n\n```\nbundle exec rake kitchen:default-ubuntu-1604\n```\n\nTo test all platforms:\n\n```\nbundle exec rake kitchen:all\n```\n\n### Publishing (maintainers only!)\n\nBump version in metadata.rb, commit and push to master!\n\n```\nbundle exec rake publish\n```\n\nas a result new tag will be created and pushed to github as well as new version\nwill be published on https://supermarket.chef.io\n\nContributing\n===========\n\nPlease do not bump version when proposing a change, no other rules ;)\n\nLicense and Author\n==================\n\nAuthor:: Seth Chisamore ()\n\nCopyright:: 2011, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "maintainer": "Opscode, Inc.", + "maintainer_email": "cookbooks@opscode.com", + "license": "Apache 2.0", + "platforms": { + "debian": ">= 0.0.0", + "ubuntu": ">= 0.0.0", + "centos": ">= 0.0.0", + "redhat": ">= 0.0.0", + "fedora": ">= 0.0.0", + "amazon": ">= 0.0.0" + }, + "dependencies": { + "apt": ">= 0.0.0", + "yum": ">= 3.0" + }, + "recommendations": { + }, + "suggestions": { + }, + "conflicting": { + }, + "providing": { + }, + "replacing": { + }, + "attributes": { + }, + "groupings": { + }, + "recipes": { + } +} \ No newline at end of file diff --git a/cookbooks/php-fpm/metadata.rb b/cookbooks/php-fpm/metadata.rb deleted file mode 100644 index e5029e0..0000000 --- a/cookbooks/php-fpm/metadata.rb +++ /dev/null @@ -1,14 +0,0 @@ -name "php-fpm" -maintainer "Opscode, Inc." -maintainer_email "cookbooks@opscode.com" -license "Apache 2.0" -description "Installs/Configures php-fpm" -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version "0.7.5" - -depends "apt" -depends "yum", ">= 3.0" - -%w{ debian ubuntu centos redhat fedora amazon }.each do |os| - supports os -end diff --git a/cookbooks/php-fpm/recipes/install.rb b/cookbooks/php-fpm/recipes/install.rb index 981b6e8..922590e 100644 --- a/cookbooks/php-fpm/recipes/install.rb +++ b/cookbooks/php-fpm/recipes/install.rb @@ -24,6 +24,8 @@ include_recipe 'apt::default' if node['platform_family'] == 'debian' if node['php-fpm']['package_name'].nil? if platform_family?("rhel", "fedora") php_fpm_package_name = "php-fpm" + elsif platform?('ubuntu') and node['platform_version'].to_f >= 16.04 + php_fpm_package_name = "php7.0-fpm" else php_fpm_package_name = "php5-fpm" end @@ -42,9 +44,16 @@ else php_fpm_service_name = node['php-fpm']['service_name'] end +service_provider = nil +# this is actually already done in chef, but is kept here for older chef releases +if platform?('ubuntu') and node['platform_version'].to_f.between?(13.10, 14.10) + service_provider = ::Chef::Provider::Service::Upstart +end + directory node['php-fpm']['log_dir'] service "php-fpm" do + provider service_provider if service_provider service_name php_fpm_service_name supports :start => true, :stop => true, :restart => true, :reload => true action [ :enable, :start ] diff --git a/cookbooks/php-fpm/recipes/repository.rb b/cookbooks/php-fpm/recipes/repository.rb index dfabb07..3d253f0 100644 --- a/cookbooks/php-fpm/recipes/repository.rb +++ b/cookbooks/php-fpm/recipes/repository.rb @@ -38,15 +38,23 @@ when 'debian' # Configure Dotdeb repos # TODO: move this to it's own 'dotdeb' cookbook? # http://www.dotdeb.org/instructions/ - if node.platform_version.to_f >= 7.0 + if node['platform_version'].to_f >= 8.0 apt_repository "dotdeb" do uri node['php-fpm']['dotdeb_repository']['uri'] - distribution "stable" + distribution "jessie" components ['all'] key node['php-fpm']['dotdeb_repository']['key'] action :add end - elsif node.platform_version.to_f >= 6.0 + elsif node['platform_version'].to_f >= 7.0 + apt_repository "dotdeb" do + uri node['php-fpm']['dotdeb_repository']['uri'] + distribution "wheezy" + components ['all'] + key node['php-fpm']['dotdeb_repository']['key'] + action :add + end + elsif node['platform_version'].to_f >= 6.0 apt_repository "dotdeb" do uri node['php-fpm']['dotdeb_repository']['uri'] distribution "squeeze" diff --git a/cookbooks/php-fpm/recipes/test.rb b/cookbooks/php-fpm/recipes/test.rb new file mode 100644 index 0000000..eff3d5f --- /dev/null +++ b/cookbooks/php-fpm/recipes/test.rb @@ -0,0 +1,3 @@ +include_recipe 'php-fpm::default' + +package 'net-tools' diff --git a/cookbooks/php-fpm/templates/default/pool.conf.erb b/cookbooks/php-fpm/templates/default/pool.conf.erb index 78cafe0..ec4fbf3 100644 --- a/cookbooks/php-fpm/templates/default/pool.conf.erb +++ b/cookbooks/php-fpm/templates/default/pool.conf.erb @@ -19,8 +19,8 @@ ; Unix user/group of processes ; Note: The user is mandatory. If the group is not set, the default user's group ; will be used. -user = <%= @user || node['php-fpm']['user'] %> -group = <%= @group || node['php-fpm']['group'] %> +user = <%= @user %> +group = <%= @group %> ; The address on which to accept FastCGI requests. ; Valid syntaxes are: @@ -30,7 +30,7 @@ group = <%= @group || node['php-fpm']['group'] %> ; specific port; ; '/path/to/unix/socket' - to listen on a unix socket. ; Note: This value is mandatory. -listen = <%= @listen || "/var/run/php-fpm-#{@pool_name}.sock" %> +listen = <%= @listen %> ; Set listen(2) backlog. ; Default Value: 128 (-1 on FreeBSD and OpenBSD) @@ -52,7 +52,7 @@ listen.owner = <%= @listen_owner %> listen.group = <%= @listen_group %> <% end %> -listen.mode = <%= @listen_mode || "0660" %> +listen.mode = <%= @listen_mode %> ; List of ipv4 addresses of FastCGI clients which are allowed to connect. ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original @@ -94,7 +94,7 @@ listen.allowed_clients = <%= @allowed_clients ? ([@allowed_clients].flatten.join ; pm.process_idle_timeout - The number of seconds after which ; an idle process will be killed. ; Note: This value is mandatory. -pm = <%= @process_manager || "ondemand" %> +pm = <%= @process_manager %> ; The number of child processes to be created when pm is set to 'static' and the ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. @@ -105,7 +105,7 @@ pm = <%= @process_manager || "ondemand" %> ; forget to tweak pm.* to fit your needs. ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' ; Note: This value is mandatory. -pm.max_children = <%= @max_children || 50 %> +pm.max_children = <%= @max_children %> <% if @process_manager == "dynamic" %> ; The number of child processes created on startup. @@ -118,12 +118,12 @@ pm.start_servers = <%= @start_servers %> ; The desired minimum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' -pm.min_spare_servers = <%= @min_spare_servers || 5 %> +pm.min_spare_servers = <%= @min_spare_servers %> ; The desired maximum number of idle server processes. ; Note: Used only when pm is set to 'dynamic' ; Note: Mandatory when pm is set to 'dynamic' -pm.max_spare_servers = <%= @max_spare_servers || 35 %> +pm.max_spare_servers = <%= @max_spare_servers %> <% end %> <% if @process_manager == "ondemand" %> @@ -137,7 +137,7 @@ pm.max_spare_servers = <%= @max_spare_servers || 35 %> ; This can be useful to work around memory leaks in 3rd party libraries. For ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. ; Default Value: 0 -pm.max_requests = <%= @max_requests || 500 %> +pm.max_requests = <%= @max_requests %> ; The URI to view the FPM status page. If this value is not set, no URI will be ; recognized as a status page. It shows the following informations: @@ -319,20 +319,28 @@ access.log = <%= node['php-fpm']['log_dir'] %>/$pool.access.log ; The log file for slow requests ; Default Value: not set ; Note: slowlog is mandatory if request_slowlog_timeout is set +<% if @slowlog %> +slowlog = <%= @slowlog %> +<% else %> ;slowlog = log/$pool.log.slow +<% end %> ; The timeout for serving a single request after which a PHP backtrace will be ; dumped to the 'slowlog' file. A value of '0s' means 'off'. ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) ; Default Value: 0 +<% if @request_slowlog_timeout %> +request_slowlog_timeout = <%=@request_slowlog_timeout %> +<% else %> ;request_slowlog_timeout = 0 +<% end %> ; The timeout for serving a single request after which the worker process will ; be killed. This option should be used when the 'max_execution_time' ini option ; does not stop script execution for some reason. A value of '0' means 'off'. ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) ; Default Value: 0 -request_terminate_timeout = <%=@request_terminate_timeout || 0 %> +request_terminate_timeout = <%=@request_terminate_timeout %> ; Set open file descriptor rlimit. ; Default Value: system defined value @@ -364,7 +372,7 @@ request_terminate_timeout = <%=@request_terminate_timeout || 0 %> ; Note: on highloaded environement, this can cause some delay in the page ; process time (several ms). ; Default Value: no -catch_workers_output = <%= @catch_workers_output || "no" %> +catch_workers_output = <%= @catch_workers_output %> <% if node['platform'] != 'ubuntu' && node['platform_version'] != '10.04' %> ; Limits the extensions of the main script FPM will allow to parse. This can @@ -374,7 +382,7 @@ catch_workers_output = <%= @catch_workers_output || "no" %> ; Note: set an empty value to allow all extensions. ; Default Value: .php ;security.limit_extensions = .php .php3 .php4 .php5 -security.limit_extensions = <%=@security_limit_extensions || ".php" %> +security.limit_extensions = <%=@security_limit_extensions %> <% end %> ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from diff --git a/cookbooks/php-fpm/test/integration/default/serverspec/pools_spec.rb b/cookbooks/php-fpm/test/integration/default/serverspec/pools_spec.rb deleted file mode 100644 index 2abb44d..0000000 --- a/cookbooks/php-fpm/test/integration/default/serverspec/pools_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'serverspec' - -set :backend, :exec - -describe port(9081) do - it { should be_listening } -end diff --git a/cookbooks/php/CHANGELOG.md b/cookbooks/php/CHANGELOG.md index b56c711..3cbd9c0 100644 --- a/cookbooks/php/CHANGELOG.md +++ b/cookbooks/php/CHANGELOG.md @@ -1,25 +1,138 @@ -php Cookbook CHANGELOG -====================== +# php Cookbook CHANGELOG + This file is used to list changes made in each version of the php cookbook. -v1.7.2 (2015-8-24) ------------------- +## 4.2.0 (2017-05-30) + +- Make sure package intalls, php-fpm, and source installs work on Amazon linux +- Avoid symlink warning in the converges +- Simplify the package install logic +- Rename the inspec test to match the suite name so it actually runs +- Test on FreeBSD 11 / Amazon Linux +- Install 5.6.30 by default on source installs + +## 4.1.0 (2017-05-30) + +- Remove class_eval usage and require Chef 12.7+ + +## 4.0.0 (2017-04-20) + +- Fix pear_channel resource to not fail on Chef 12.5 and 12.6 +- Remove support for RHEL 5 as it is now EOL +- Resolve Amazon Linux failures on Chef 13 +- Convert fpm_pool to a custom resource +- Fix php_pear failures on Chef 13 +- Remove non-functional support for Windows +- Remove redundant Ubuntu version checks in the php_pear provider +- Expand testing to test all of the resources + +## 3.1.1 (2017-04-20) + +- Use the cookbook attribute as the default value of pear_channel pear property to provide better platform support + +## 3.1.0 (2017-04-10) + +- Use multi-package installs on supported platform_family(rhel debian suse amazon) +- Use a SPDX standardized license string in the metadata +- Update specs for the new Fauxhai data + +## 3.0.0 (2017-03-27) + +- Converted pear_channel LWRP into custom resource +- Removed use of pear node attribute from pear_channel resource +- Fix cookstyle issue with missing line on metadata.rb +- Clean up kitchen.dokken.yml file to eliminate duplication of testing suites. +- Eliminate duplicated resource from test cookbook that is in the default recipe. +- Rename php-test to standard cookbook testing cookbook of "test" +- Remove EOL ubuntu platform logic + +**NOTE** Windows package installation is currently broken. + +## 2.2.1 (2017-02-21) + +- Fix double definition of ['php']['packages'] for rhel. + +## 2.2.0 (2016-12-12) + +- Use multipackage for installs to speed up chef runs +- Use all CPUs when building from source +- Remove need for apt/yum in testing +- Add opensuse to the metadata +- Migrate to inspec for integration testing + +## 2.1.1 (2016-09-15) + +- Fix recompile un-pack php creates +- Resolve cookstyle warnings + +## 2.1.0 (2016-09-14) + +- Fix source php version check +- Require Chef 12.1 not 12.0 + +## 2.0.0 (2016-09-07) + +- Require Chef 12+ +- Remove the dependency on the Windows cookbook which isn't necessary with Chef 12+ + +## 1.10.1 (2016-08-30) + +- [fix] bug fixes related with Ubuntu 16.04 and PHP 7 support +- adding validator to listen attribute +- Fix node.foo.bar warnings + +## v1.10.0 (2016-07-27) + +- PR #167 Preventing user specified pool of www from being deleted at the end of the chef run on the first install +- PR #122 Add recipe for php module_imap +- PR #172 Fix uninstall action for resource php_fpm_pool + +## v1.9.0 (2016-05-12) + +Special thanks to @ThatGerber for getting the PR for this release together + +- Added support for Ubuntu 16.04 and PHP 7 +- Added support for different listen user/groups with FPM +- Cleaned up resource notification in the pear_channel provider to simplify code +- Fixed Ubuntu 14.04+ not being able to find the GMP library + +## v1.8.0 (2016-02-25) + +- Bumped the source install default version from 5.5.9 to 5.6.13 +- Added a chefignore file to limit the files uploaded to the Chef server +- Added source_url and issues_url to the metadata.rb +- Added additional Chefspec matchers +- Added a Chef standard rubocop.yml file and resolved warnings +- Added serverspec for integration testing +- Remove legacy cloud Test Kitchen configs +- Added testing in Travis CI with kitchen-docker +- Added additional test suites to the Test Kitchen config +- Updated contributing and testing documentation +- Updated testing gem dependencies to the latest +- Added maintainers.md and maintainers.toml files +- Remove gitter chat from the readme +- Add cookbook version badge to the readme +- Added Fedora as a supported platform in the readme +- Add missing cookbook dependencies to the readme + +## v1.7.2 (2015-8-24) + - Correct spelling in fpm_pool_start_servers (was servres) -v1.7.1 (2015-8-17) ------------------- +## v1.7.1 (2015-8-17) + - Correct permissions on ext_conf_dir folder (644 -> 755) -v1.7.0 (2015-7-31) ------------------- +## v1.7.0 (2015-7-31) + - NOTICE - This version changes the way the ['php']['directives'] is placed into configuration files. Quotes are no longer automatically placed around these aditional directives. Please take care when rolling out this version. - Allow additional PHP FPM config - Add recipe to recompile PHP from source - Move source dependencies to attributes file - Misc bug fixes -v1.6.0 (2015-7-6) ------------------ +## v1.6.0 (2015-7-6) + - Added ChefSpec matchers - Added basic PHP-FPM Support (Pre-Release) - Added support for FreeBSD @@ -27,138 +140,134 @@ v1.6.0 (2015-7-6) - Update cookbook to use php5enmod on supported platforms - Allow users to override php-mysql package -v1.5.0 (2014-10-06) -------------------- +## v1.5.0 (2014-10-06) + - Adding package_options attribute, utilizing in package resource -v1.4.6 (2014-03-19) -------------------- +## v1.4.6 (2014-03-19) + - [COOK-4436] - Test this cookbook, not yum. Also test Fedora 20. - [COOK-4427] - Add oracle as supported operating system +## v1.4.4 (2014-03-12) -v1.4.4 (2014-03-12) -------------------- - [COOK-4393] - Fix convergence bug in source install +## v1.4.2 (2014-02-27) -v1.4.2 (2014-02-27) -------------------- [COOK-4300] - Simplified and fixed pear/pecl logic. [Fixes #56 / #57] +## v1.4.0 (2014-02-27) -v1.4.0 (2014-02-27) -------------------- [COOK-3639] - Allow users to specify php.ini source template +## v1.3.14 (2014-02-21) -v1.3.14 (2014-02-21) --------------------- ### Bug + - **[COOK-4186](https://tickets.opscode.com/browse/COOK-4186)** - Upgrade_package concatenates an empty version string when version is not set or is empty. +## v1.3.12 (2014-01-28) -v1.3.12 (2014-01-28) --------------------- Fix github issue 'Cannot find a resource for preferred_state' +## v1.3.10 -v1.3.10 -------- Fixing my stove +## v1.3.8 -v1.3.8 ------- Version bump to ensure artifact sanity +## v1.3.6 -v1.3.6 ------- Version bump for toolchain +## v1.3.4 -v1.3.4 ------- Adding platform_family check to include_recipe in source.rb +## v1.3.2 -v1.3.2 ------- Fixing style cops. Updating test harness +## v1.3.0 -v1.3.0 ------- ### Bug + - **[COOK-3479](https://tickets.opscode.com/browse/COOK-3479)** - Added Windows support to PHP - **[COOK-2909](https://tickets.opscode.com/browse/COOK-2909)** - Warnings about Chef::Exceptions::ShellCommandFailed is deprecated +## v1.2.6 -v1.2.6 ------- ### Bug + - **[COOK-3628](https://tickets.opscode.com/browse/COOK-3628)** - Fix PHP download URL - **[COOK-3568](https://tickets.opscode.com/browse/COOK-3568)** - Fix Test Kitchen tests - **[COOK-3402](https://tickets.opscode.com/browse/COOK-3402)** - When the `ext_dir` setting is present, configure php properly for the source recipe - **[COOK-2926](https://tickets.opscode.com/browse/COOK-2926)** - Fix pear package detection when installing specific version +## v1.2.4 -v1.2.4 ------- ### Improvement + - **[COOK-3047](https://tickets.opscode.com/browse/COOK-3047)** - Sort directives in `php.ini` - **[COOK-2928](https://tickets.opscode.com/browse/COOK-2928)** - Abstract `php.ini` directives into variables ### Bug + - **[COOK-2378](https://tickets.opscode.com/browse/COOK-2378)** - Fix `php_pear` for libevent -v1.2.2 ------- +## v1.2.2 + ### Bug + - [COOK-3050]: `lib_dir` declared in wrong place for redhat - [COOK-3102]: remove fileinfo recipe from php cookbook ### Improvement + - [COOK-3101]: use a method to abstract range of "el 5" versions in php recipes -v1.2.0 ------- +## v1.2.0 + ### Improvement + - [COOK-2516]: Better support for SUSE distribution for php cookbook - [COOK-3035]: update php::source to install 5.4.15 by default ### Bug + - [COOK-2463]: PHP PEAR Provider Installs Most Recent Version, Without Respect to Preferred State - [COOK-2514]: php_pear: does not handle more exotic version strings -v1.1.8 ------- +## v1.1.8 + - [COOK-1998] - Enable override of PHP packages in attributes -v1.1.6 ------- +## v1.1.6 + - [COOK-2324] - adds Oracle linux support -v1.1.4 ------- +## v1.1.4 + - [COOK-2106] - `php_pear` cannot find available packages -v1.1.2 ------- +## v1.1.2 + - [COOK-1803] - use better regexp to match package name - [COOK-1926] - support Amazon linux -v1.1.0 ------- +## v1.1.0 + - [COOK-543] - php.ini template should be configurable - [COOK-1067] - support for PECL zend extensions - [COOK-1193] - update package names for EPEL 6 - [COOK-1348] - rescue Mixlib::ShellOut::ShellCommandFailed (chef 0.10.10) - [COOK-1465] - fix pear extension template -v1.0.2 ------- +## v1.0.2 + - [COOK-993] Add mhash-devel to centos php source libs - [COOK-989] - bump version of php to 5.3.10 - Also download the .tar.gz instead of .tar.bz2 as bzip2 may not be in the base OS (e.g., CentOS 6 minimal) diff --git a/cookbooks/yum-mysql-community/CONTRIBUTING.md b/cookbooks/php/CONTRIBUTING.md similarity index 100% rename from cookbooks/yum-mysql-community/CONTRIBUTING.md rename to cookbooks/php/CONTRIBUTING.md diff --git a/cookbooks/php/MAINTAINERS.md b/cookbooks/php/MAINTAINERS.md new file mode 100644 index 0000000..645ed14 --- /dev/null +++ b/cookbooks/php/MAINTAINERS.md @@ -0,0 +1,15 @@ + + +# Maintainers + +This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. + +Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. + +# Project Maintainer +* [Tim Smith](https://github.com/tas50) + +# Maintainers +* [Jennifer Davis](https://github.com/sigje) +* [Tim Smith](https://github.com/tas50) +* [Thom May](https://github.com/thommay) diff --git a/cookbooks/php/README.md b/cookbooks/php/README.md index cdd1195..8227d55 100644 --- a/cookbooks/php/README.md +++ b/cookbooks/php/README.md @@ -1,59 +1,64 @@ -php Cookbook -============ +# php Cookbook -[![Join the chat at https://gitter.im/opscode-cookbooks/php](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/opscode-cookbooks/php?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Cookbook Version](https://img.shields.io/cookbook/v/php.svg)](https://supermarket.chef.io/cookbooks/php) -[![Build Status](https://travis-ci.org/opscode-cookbooks/php.svg?branch=master)](https://travis-ci.org/opscode-cookbooks/php) +[![Build Status](https://travis-ci.org/chef-cookbooks/php.svg?branch=master)](http://travis-ci.org/chef-cookbooks/php) [![Cookbook Version](https://img.shields.io/cookbook/v/php.svg)](https://supermarket.chef.io/cookbooks/php) -Installs and configures PHP 5.3 and the PEAR package management system. Also includes LWRPs for managing PEAR (and PECL) packages, PECL channels, and PHP-FPM pools. +It installs and configures PHP and the PEAR package management system. Also includes resources for managing PEAR (and PECL) packages, PECL channels, and PHP-FPM pools. + +## Requirements -Requirements ------------- ### Platforms + - Debian, Ubuntu -- CentOS, Red Hat, Fedora, Amazon Linux -- Microsoft Windows +- CentOS, Red Hat, Oracle, Scientific, Amazon Linux +- Fedora + +### Chef + +- Chef 12.7+ ### Cookbooks + - build-essential - xml - mysql -These cookbooks are only used when building PHP from source. +## Attributes - -Attributes ----------- - `node['php']['install_method']` = method to install php with, default `package`. - `node['php']['directives']` = Hash of directives and values to append to `php.ini`, default `{}`. +- `node['php']['pear']` = Name of the pear executable to use, default `pear`. The file also contains the following attribute types: -* platform specific locations and settings. -* source installation settings +- platform specific locations and settings. +- source installation settings +## Resource/Provider -Resource/Provider ------------------ This cookbook includes LWRPs for managing: - PEAR channels - PEAR/PECL packages ### `php_pear_channel` -[PEAR Channels](http://pear.php.net/manual/en/guide.users.commandline.channels.php) are alternative sources for PEAR packages. This LWRP provides and easy way to manage these channels. + +[PEAR Channels](http://pear.php.net/manual/en/guide.users.commandline.channels.php) are alternative sources for PEAR packages. This resource provides and easy way to manage these channels. #### Actions + - :discover: Initialize a channel from its server. -- :add: Add a channel to the channel list, usually only used to add private channels. Public channels are usually added using the `:discover` action +- :add: Add a channel to the channel list, usually only used to add private channels. Public channels are usually added using the `:discover` action - :update: Update an existing channel - :remove: Remove a channel from the List #### Attribute Parameters + - channel_name: name attribute. The name of the channel to discover - channel_xml: the channel.xml file of the channel you are adding +- pear: pear binary, default: pear #### Examples + ```ruby # discover the horde channel php_pear_channel "pear.horde.org" do @@ -82,23 +87,27 @@ end ``` ### `php_pear` -[PEAR](http://pear.php.net/) is a framework and distribution system for reusable PHP components. [PECL](http://pecl.php.net/) is a repository for PHP Extensions. PECL contains C extensions for compiling into PHP. As C programs, PECL extensions run more efficiently than PEAR packages. PEARs and PECLs use the same packaging and distribution system. As such this LWRP is clever enough to abstract away the small differences and can be used for managing either. This LWRP also creates the proper module .ini file for each PECL extension at the correct location for each supported platform. + +[PEAR](http://pear.php.net/) is a framework and distribution system for reusable PHP components. [PECL](http://pecl.php.net/) is a repository for PHP Extensions. PECL contains C extensions for compiling into PHP. As C programs, PECL extensions run more efficiently than PEAR packages. PEARs and PECLs use the same packaging and distribution system. As such this LWRP is clever enough to abstract away the small differences and can be used for managing either. This LWRP also creates the proper module .ini file for each PECL extension at the correct location for each supported platform. #### Actions -- :install: Install a pear package - if version is provided, install that specific version -- :upgrade: Upgrade a pear package - if version is provided, upgrade to that specific version -- :remove: Remove a pear package -- :purge: Purge a pear package (this usually entails removing configuration files as well as the package itself). With pear packages this behaves the same as `:remove` + +- `:install`: Install a pear package - if version is provided, install that specific version +- `:upgrade`: Upgrade a pear package - if version is provided, upgrade to that specific version +- `:remove`: Remove a pear package +- `:purge`: Purge a pear package (this usually entails removing configuration files as well as the package itself). With pear packages this behaves the same as `:remove` #### Attribute Parameters -- package_name: name attribute. The name of the pear package to install -- version: the version of the pear package to install/upgrade. If no version is given latest is assumed. -- preferred_state: PEAR by default installs stable packages only, this allows you to install pear packages in a devel, alpha or beta state -- directives: extra extension directives (settings) for a pecl. on most platforms these usually get rendered into the extension's .ini file -- zend_extensions: extension filenames which should be loaded with zend_extension. -- options: Add additional options to the underlying pear package command + +- `package_name`: name attribute. The name of the pear package to install +- version: the version of the pear package to install/upgrade. If no version is given latest is assumed. +- `preferred_state`: PEAR by default installs stable packages only, this allows you to install pear packages in a devel, alpha or beta state +- `directives`: extra extension directives (settings) for a pecl. on most platforms these usually get rendered into the extension's .ini file +- `zend_extensions`: extension filenames which should be loaded with zend_extension. +- o`ptions`: Add additional options to the underlying pear package command #### Examples + ```ruby # upgrade a pear php_pear "XML_RPC" do @@ -156,35 +165,34 @@ end ``` ### `php_fpm_pool` -Installs the `php-fpm` package appropriate for your distro (if using packages) -and configures a FPM pool for you. Currently only supported in Debian-family -operating systems and CentOS 7 (or at least tested with such, YMMV if you are -using source). + +Installs the `php-fpm` package appropriate for your distro (if using packages) and configures a FPM pool for you. Currently only supported in Debian-family operating systems and CentOS 7 (or at least tested with such, YMMV if you are using source). Please consider FPM functionally pre-release, and test it thoroughly in your environment before using it in production -More info: http://php.net/manual/en/install.fpm.php +More info: #### Actions -- :install: Installs the FPM pool (default). -- :uninstall: Removes the FPM pool. + +- `:install`: Installs the FPM pool (default). +- `:uninstall`: Removes the FPM pool. #### Attribute Parameters -- pool_name: name attribute. The name of the FPM pool. -- listen: The listen address. Default: `/var/run/php5-fpm.sock` -- user: The user to run the FPM under. Default should be the webserver user for - your distro. -- group: The group to run the FPM under. Default should be the webserver group - for your distro. -- process_manager: Process manager to use - see - http://php.net/manual/en/install.fpm.configuration.php. Default: `dynamic` -- max_children: Max children to scale to. Default: 5 -- start_servers: Number of servers to start the pool with. Default: 2 -- min_spare_servers: Minimum number of servers to have as spares. Default: 1 -- max_spare_servers: Maximum number of servers to have as spares. Default: 3 -- chdir: The startup working directory of the pool. Default: `/` + +- `pool_name`: name attribute. The name of the FPM pool. +- `listen`: The listen address. Default: `/var/run/php5-fpm.sock` +- `user`: The user to run the FPM under. Default should be the webserver user for your distro. +- `group`: The group to run the FPM under. Default should be the webserver group for your distro. +- `process_manager`: Process manager to use - see . Default: `dynamic` +- `max_children`: Max children to scale to. Default: 5 +- `start_servers`: Number of servers to start the pool with. Default: 2 +- `min_spare_servers`: Minimum number of servers to have as spares. Default: 1 +- `max_spare_servers`: Maximum number of servers to have as spares. Default: 3 +- `chdir`: The startup working directory of the pool. Default: `/` +- `additional_config`: Additional parameters in JSON. Default: {} #### Examples + ```ruby # Install a FPM pool named "default" php_fpm_pool "default" do @@ -192,34 +200,38 @@ php_fpm_pool "default" do end ``` -Recipes -------- +## Recipes + ### default -Include the default recipe in a run list, to get `php`. By default `php` is installed from packages but this can be changed by using the `install_method` attribute. + +Include the default recipe in a run list, to get `php`. By default `php` is installed from packages but this can be changed by using the `install_method` attribute. ### package + This recipe installs PHP from packages. ### source + This recipe installs PHP from source. +## Deprecated Recipes -Deprecated Recipes ------------------- The following recipes are deprecated and will be removed from a future version of this cookbook. - `module_apc` +- `module_apcu` - `module_curl` - `module_fileinfo` - `module_fpdf` - `module_gd` +- `module_imap` - `module_ldap` - `module_memcache` - `module_mysql` - `module_pgsql` - `module_sqlite3` -The installation of the php modules in these recipes can now be accomplished by installing from a native package or via the new php_pear LWRP. For example, the functionality of the `module_memcache` recipe can be enabled in the following ways: +The installation of the php modules in these recipes can now be accomplished by installing from a native package or via the new php_pear LWRP. For example, the functionality of the `module_memcache` recipe can be enabled in the following ways: ```ruby # using apt @@ -233,10 +245,11 @@ php_pear "memcache" do end ``` +## Usage -Usage ------ -Simply include the `php` recipe where ever you would like php installed. To install from source override the `node['php']['install_method']` attribute with in a role: +Simply include the `php` recipe where ever you would like php installed. To install from source override the `node['php']['install_method']` attribute with in a role or wrapper cookbook: + +### Role example: ```ruby name "php" @@ -251,47 +264,13 @@ run_list( ) ``` +## License & Authors -Development ------------ -This section details "quick development" steps. For a detailed explanation, see [[Contributing.md]]. +**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io)) -1. Clone this repository from GitHub: - - $ git clone git@github.com:opscode-cookbooks/php.git - -2. Create a git branch - - $ git checkout -b my_bug_fix - -3. Install dependencies: - - $ bundle install - -4. Make your changes/patches/fixes, committing appropiately -5. **Write tests** -6. Run the tests: - - `bundle exec foodcritic -f any .` - - `bundle exec rspec` - - `bundle exec rubocop` - - `bundle exec kitchen test` - - In detail: - - Foodcritic will catch any Chef-specific style errors - - RSpec will run the unit tests - - Rubocop will check for Ruby-specific style errors - - Test Kitchen will run and converge the recipes - - -License & Authors ------------------ -- Author:: Seth Chisamore () -- Author:: Joshua Timberman () -- Author:: Julian C. Dunn () - -```text -Copyright:: 2013-2014, Chef Software, Inc. +**Copyright:** 2008-2017, Chef Software, Inc. +``` Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -304,85 +283,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` - -Note: This cookbook contains a modified copy of `go-phar.pear` for use on the -Microsoft Windows platform only to correct an (upstream bug)[http://pear.php.net/bugs/bug.php?id=16644]. The original -`go-pear.phar` is licensed under the (PHP License version 2.02)[http://www.php.net/license/2_02.txt]: - -``` --------------------------------------------------------------------- - The PHP License, version 2.02 -Copyright (c) 1999 - 2002 The PHP Group. All rights reserved. --------------------------------------------------------------------- - -Redistribution and use in source and binary forms, with or without -modification, is permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - 3. The name "PHP" must not be used to endorse or promote products - derived from this software without prior permission from the - PHP Group. This does not apply to add-on libraries or tools - that work in conjunction with PHP. In such a case the PHP - name may be used to indicate that the product supports PHP. - - 4. The PHP Group may publish revised and/or new versions of the - license from time to time. Each version will be given a - distinguishing version number. - Once covered code has been published under a particular version - of the license, you may always continue to use it under the - terms of that version. You may also choose to use such covered - code under the terms of any subsequent version of the license - published by the PHP Group. No one other than the PHP Group has - the right to modify the terms applicable to covered code created - under this License. - - 5. Redistributions of any form whatsoever must retain the following - acknowledgment: - "This product includes PHP, freely available from - http://www.php.net/". - - 6. The software incorporates the Zend Engine, a product of Zend - Technologies, Ltd. ("Zend"). The Zend Engine is licensed to the - PHP Association (pursuant to a grant from Zend that can be - found at http://www.php.net/license/ZendGrant/) for - distribution to you under this license agreement, only as a - part of PHP. In the event that you separate the Zend Engine - (or any portion thereof) from the rest of the software, or - modify the Zend Engine, or any portion thereof, your use of the - separated or modified Zend Engine software shall not be governed - by this license, and instead shall be governed by the license - set forth at http://www.zend.com/license/ZendLicense/. - - - -THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND -ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP -DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------------------------- - -This software consists of voluntary contributions made by many -individuals on behalf of the PHP Group. - -The PHP Group can be contacted via Email at group@php.net. - -For more information on the PHP Group and the PHP project, -please see . -``` diff --git a/cookbooks/php/attributes/default.rb b/cookbooks/php/attributes/default.rb index 233322d..58a2dc6 100644 --- a/cookbooks/php/attributes/default.rb +++ b/cookbooks/php/attributes/default.rb @@ -1,9 +1,8 @@ # -# Author:: Seth Chisamore () -# Cookbook Name:: php -# Attribute:: default +# Cookbook:: php +# Attributes:: default # -# Copyright 2011-2014, Chef Software, Inc. +# Copyright:: 2011-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,42 +25,58 @@ default['php']['bin'] = 'php' default['php']['pear'] = 'pear' default['php']['pecl'] = 'pecl' +default['php']['version'] = '5.6.30' + +default['php']['url'] = 'http://us1.php.net/get' +default['php']['checksum'] = '8bc7d93e4c840df11e3d9855dcad15c1b7134e8acf0cf3b90b932baea2d0bde2' +default['php']['prefix_dir'] = '/usr/local' +default['php']['enable_mod'] = '/usr/sbin/php5enmod' +default['php']['disable_mod'] = '/usr/sbin/php5dismod' + +default['php']['ini']['template'] = 'php.ini.erb' +default['php']['ini']['cookbook'] = 'php' + +default['php']['fpm_socket'] = '/var/run/php5-fpm.sock' +default['php']['curl']['package'] = 'php5-curl' +default['php']['apc']['package'] = 'php5-apc' +default['php']['apcu']['package'] = 'php5-apcu' +default['php']['gd']['package'] = 'php5-gd' +default['php']['ldap']['package'] = 'php5-ldap' +default['php']['pgsql']['package'] = 'php5-pgsql' +default['php']['sqlite']['package'] = 'php5-sqlite3' + case node['platform_family'] -when 'rhel', 'fedora' +when 'rhel', 'fedora', 'amazon' lib_dir = node['kernel']['machine'] =~ /x86_64/ ? 'lib64' : 'lib' default['php']['conf_dir'] = '/etc' default['php']['ext_conf_dir'] = '/etc/php.d' default['php']['fpm_user'] = 'nobody' default['php']['fpm_group'] = 'nobody' - default['php']['ext_dir'] = "/usr/#{lib_dir}/php/modules" - default['php']['src_deps'] = %w(bzip2-devel libc-client-devel curl-devel freetype-devel gmp-devel libjpeg-devel krb5-devel libmcrypt-devel libpng-devel openssl-devel t1lib-devel mhash-devel) - if node['platform_version'].to_f < 6 - default['php']['packages'] = %w(php53 php53-devel php53-cli php-pear) - default['php']['mysql']['package'] = 'php53-mysql' - else - default['php']['packages'] = %w(php php-devel php-cli php-pear) - default['php']['mysql']['package'] = 'php-mysql' + default['php']['fpm_listen_user'] = 'nobody' + default['php']['fpm_listen_group'] = 'nobody' + default['php']['ext_dir'] = "/usr/#{lib_dir}/php/modules" + if node['platform'] == 'amazon' # amazon names their packages with versions + default['php']['src_deps'] = %w(bzip2-devel libc-client-devel curl-devel freetype-devel gmp-devel libjpeg-devel krb5-devel libmcrypt-devel libpng-devel openssl-devel t1lib-devel) + default['php']['packages'] = %w(php56 php56-devel php-pear) + default['php']['fpm_package'] = 'php56-fpm' + else # redhat does not name their packages with version on RHEL 6+ + default['php']['src_deps'] = %w(bzip2-devel libc-client-devel curl-devel freetype-devel gmp-devel libjpeg-devel krb5-devel libmcrypt-devel libpng-devel openssl-devel t1lib-devel mhash-devel) + default['php']['packages'] = %w(php php-devel php-cli php-pear) default['php']['fpm_package'] = 'php-fpm' - default['php']['fpm_pooldir'] = '/etc/php-fpm.d' - default['php']['fpm_default_conf'] = '/etc/php-fpm.d/www.conf' - default['php']['fpm_service'] = 'php-fpm' - if node['php']['install_method'] == 'package' - default['php']['fpm_user'] = 'apache' - default['php']['fpm_group'] = 'apache' - end + end + default['php']['mysql']['package'] = 'php-mysql' + default['php']['fpm_pooldir'] = '/etc/php-fpm.d' + default['php']['fpm_default_conf'] = '/etc/php-fpm.d/www.conf' + default['php']['fpm_service'] = 'php-fpm' + if node['php']['install_method'] == 'package' + default['php']['fpm_user'] = 'apache' + default['php']['fpm_group'] = 'apache' + default['php']['fpm_listen_user'] = 'apache' + default['php']['fpm_listen_group'] = 'apache' end when 'debian' - default['php']['conf_dir'] = '/etc/php5/cli' - case node['platform'] - when 'ubuntu' - if node['platform_version'].to_f >= 12.10 - default['php']['ext_conf_dir'] = '/etc/php5/mods-available' - else - default['php']['ext_conf_dir'] = '/etc/php5/conf.d' - end - else - default['php']['ext_conf_dir'] = '/etc/php5/conf.d' - end + default['php']['conf_dir'] = '/etc/php5/cli' + default['php']['ext_conf_dir'] = '/etc/php5/conf.d' default['php']['src_deps'] = %w(libbz2-dev libc-client2007e-dev libcurl4-gnutls-dev libfreetype6-dev libgmp3-dev libjpeg62-dev libkrb5-dev libmcrypt-dev libpng12-dev libssl-dev libt1-dev) default['php']['packages'] = %w(php5-cgi php5 php5-dev php5-cli php-pear) default['php']['mysql']['package'] = 'php5-mysql' @@ -69,43 +84,63 @@ when 'debian' default['php']['fpm_pooldir'] = '/etc/php5/fpm/pool.d' default['php']['fpm_user'] = 'www-data' default['php']['fpm_group'] = 'www-data' - default['php']['fpm_service'] = 'php5-fpm' - default['php']['fpm_default_conf'] = '/etc/php5/fpm/pool.d/www.conf' + default['php']['fpm_listen_user'] = 'www-data' + default['php']['fpm_listen_group'] = 'www-data' + default['php']['fpm_service'] = 'php5-fpm' + default['php']['fpm_default_conf'] = '/etc/php5/fpm/pool.d/www.conf' + case node['platform'] + when 'ubuntu' + case node['platform_version'].to_f + when 16.04 + default['php']['version'] = '7.0.4' + default['php']['checksum'] = 'f6cdac2fd37da0ac0bbcee0187d74b3719c2f83973dfe883d5cde81c356fe0a8' + default['php']['conf_dir'] = '/etc/php/7.0/cli' + default['php']['src_deps'] = %w(libbz2-dev libc-client2007e-dev libcurl4-gnutls-dev libfreetype6-dev libgmp3-dev libjpeg62-dev libkrb5-dev libmcrypt-dev libpng12-dev libssl-dev pkg-config) + default['php']['packages'] = %w(php7.0-cgi php7.0 php7.0-dev php7.0-cli php-pear) + default['php']['mysql']['package'] = 'php7.0-mysql' + default['php']['curl']['package'] = 'php7.0-curl' + default['php']['apc']['package'] = 'php-apc' + default['php']['apcu']['package'] = 'php-apcu' + default['php']['gd']['package'] = 'php7.0-gd' + default['php']['ldap']['package'] = 'php7.0-ldap' + default['php']['pgsql']['package'] = 'php7.0-pgsql' + default['php']['sqlite']['package'] = 'php7.0-sqlite3' + default['php']['fpm_package'] = 'php7.0-fpm' + default['php']['fpm_pooldir'] = '/etc/php/7.0/fpm/pool.d' + default['php']['fpm_service'] = 'php7.0-fpm' + default['php']['fpm_socket'] = '/var/run/php/php7.0-fpm.sock' + default['php']['fpm_default_conf'] = '/etc/php/7.0/fpm/pool.d/www.conf' + default['php']['enable_mod'] = '/usr/sbin/phpenmod' + default['php']['disable_mod'] = '/usr/sbin/phpdismod' + default['php']['ext_conf_dir'] = '/etc/php/7.0/mods-available' + when 13.04..15.10 + default['php']['ext_conf_dir'] = '/etc/php5/mods-available' + end + when 'debian' + if node['platform_version'].to_i == 8 + default['php']['ext_conf_dir'] = '/etc/php5/mods-available' + end + end when 'suse' default['php']['conf_dir'] = '/etc/php5/cli' default['php']['ext_conf_dir'] = '/etc/php5/conf.d' default['php']['src_deps'] = %w(libbz2-dev libc-client2007e-dev libcurl4-gnutls-dev libfreetype6-dev libgmp3-dev libjpeg62-dev libkrb5-dev libmcrypt-dev libpng12-dev libssl-dev libt1-dev) default['php']['fpm_user'] = 'wwwrun' default['php']['fpm_group'] = 'www' - default['php']['packages'] = %w(apache2-mod_php5 php5-pear) + default['php']['fpm_listen_user'] = 'wwwrun' + default['php']['fpm_listen_group'] = 'www' + default['php']['packages'] = %w(apache2-mod_php5 php5-pear) default['php']['mysql']['package'] = 'php5-mysql' lib_dir = node['kernel']['machine'] =~ /x86_64/ ? 'lib64' : 'lib' -when 'windows' - default['php']['windows']['msi_name'] = 'PHP 5.3.28' - default['php']['windows']['msi_source'] = 'http://windows.php.net/downloads/releases/php-5.3.28-nts-Win32-VC9-x86.msi' - default['php']['bin'] = 'php.exe' - default['php']['conf_dir'] = 'C:\Program Files (x86)\PHP' - default['php']['ext_conf_dir'] = node['php']['conf_dir'] - # These extensions are installed by default by the GUI MSI - default['php']['packages'] = %w(cgi ScriptExecutable PEAR - iis4FastCGI ext_php_bz2 ext_php_curl - ext_php_exif ext_php_gd2 ext_php_gettext - ext_php_gmp ext_php_imap ext_php_mbstring - ext_php_mysql ext_php_mysqli ext_php_openssl - ext_php_pdo_mysql ext_php_pdo_odbc ext_php_pdo_sqlite - ext_php_pgsql ext_php_soap ext_php_sockets - ext_php_sqlite3 ext_php_tidy ext_php_xmlrpc - ) - default['php']['package_options'] = '' # Use this to customise your yum or apt command - default['php']['pear'] = 'pear.bat' - default['php']['pecl'] = 'pecl.bat' when 'freebsd' default['php']['conf_dir'] = '/usr/local/etc' default['php']['ext_conf_dir'] = '/usr/local/etc/php' default['php']['src_deps'] = %w(libbz2-dev libc-client2007e-dev libcurl4-gnutls-dev libfreetype6-dev libgmp3-dev libjpeg62-dev libkrb5-dev libmcrypt-dev libpng12-dev libssl-dev libt1-dev) default['php']['fpm_user'] = 'www' default['php']['fpm_group'] = 'www' - default['php']['packages'] = %w( php56 pear ) + default['php']['fpm_listen_user'] = 'www' + default['php']['fpm_listen_group'] = 'www' + default['php']['packages'] = %w( php56 pear ) default['php']['mysql']['package'] = 'php56-mysqli' else default['php']['conf_dir'] = '/etc/php5/cli' @@ -117,19 +152,14 @@ else default['php']['mysql']['package'] = 'php5-mysql' end -default['php']['url'] = 'http://us1.php.net/get' -default['php']['version'] = '5.5.9' -default['php']['checksum'] = '378de162efdaeeb725ed38d7fe956c9f0b9084ff' -default['php']['prefix_dir'] = '/usr/local' - -default['php']['configure_options'] = %W(--prefix=#{php['prefix_dir']} +default['php']['configure_options'] = %W(--prefix=#{node['php']['prefix_dir']} --with-libdir=#{lib_dir} - --with-config-file-path=#{php['conf_dir']} - --with-config-file-scan-dir=#{php['ext_conf_dir']} + --with-config-file-path=#{node['php']['conf_dir']} + --with-config-file-scan-dir=#{node['php']['ext_conf_dir']} --with-pear --enable-fpm - --with-fpm-user=#{php['fpm_user']} - --with-fpm-group=#{php['fpm_group']} + --with-fpm-user=#{node['php']['fpm_user']} + --with-fpm-group=#{node['php']['fpm_group']} --with-zlib --with-openssl --with-kerberos @@ -159,6 +189,3 @@ default['php']['configure_options'] = %W(--prefix=#{php['prefix_dir']} --with-sqlite3 --with-pdo-mysql --with-pdo-sqlite) - -default['php']['ini']['template'] = 'php.ini.erb' -default['php']['ini']['cookbook'] = 'php' diff --git a/cookbooks/php/files/windows/go-pear.phar b/cookbooks/php/files/windows/go-pear.phar deleted file mode 100644 index b3065c0..0000000 --- a/cookbooks/php/files/windows/go-pear.phar +++ /dev/null @@ -1,98480 +0,0 @@ - - * @author Greg Beaver - * @link http://www.synapticmedia.net Synaptic Media - * @version Id: Archive.php,v 1.52 2007/09/01 20:28:14 cellog Exp $ - * @package PHP_Archive - * @category PHP - */ - -class PHP_Archive -{ - const GZ = 0x00001000; - const BZ2 = 0x00002000; - const SIG = 0x00010000; - const SHA1 = 0x0002; - const MD5 = 0x0001; - /** - * Whether this archive is compressed with zlib - * - * @var bool - */ - private $_compressed; - /** - * @var string Real path to the .phar archive - */ - private $_archiveName = null; - /** - * Current file name in the phar - * @var string - */ - protected $currentFilename = null; - /** - * Length of current file in the phar - * @var string - */ - protected $internalFileLength = null; - /** - * Current file statistics (size, creation date, etc.) - * @var string - */ - protected $currentStat = null; - /** - * @var resource|null Pointer to open .phar - */ - protected $fp = null; - /** - * @var int Current Position of the pointer - */ - protected $position = 0; - - /** - * Map actual realpath of phars to meta-data about the phar - * - * Data is indexed by the alias that is used by internal files. In other - * words, if a file is included via: - * - * require_once 'phar://PEAR.phar/PEAR/Installer.php'; - * - * then the alias is "PEAR.phar" - * - * Information stored is a boolean indicating whether this .phar is compressed - * with zlib, another for bzip2, phar-specific meta-data, and - * the precise offset of internal files - * within the .phar, used with the {@link $_manifest} to load actual file contents - * @var array - */ - private static $_pharMapping = array(); - /** - * Map real file paths to alias used - * - * @var array - */ - private static $_pharFiles = array(); - /** - * File listing for the .phar - * - * The manifest is indexed per phar. - * - * Files within the .phar are indexed by their relative path within the - * .phar. Each file has this information in its internal array - * - * - 0 = uncompressed file size - * - 1 = timestamp of when file was added to phar - * - 2 = offset of file within phar relative to internal file's start - * - 3 = compressed file size (actual size in the phar) - * @var array - */ - private static $_manifest = array(); - /** - * Absolute offset of internal files within the .phar, indexed by absolute - * path to the .phar - * - * @var array - */ - private static $_fileStart = array(); - /** - * file name of the phar - * - * @var string - */ - private $_basename; - - - /** - * Default MIME types used for the web front controller - * - * @var array - */ - public static $defaultmimes = array( - 'aif' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'arc' => 'application/octet-stream', - 'arj' => 'application/octet-stream', - 'art' => 'image/x-jg', - 'asf' => 'video/x-ms-asf', - 'asx' => 'video/x-ms-asf', - 'avi' => 'video/avi', - 'bin' => 'application/octet-stream', - 'bm' => 'image/bmp', - 'bmp' => 'image/bmp', - 'bz2' => 'application/x-bzip2', - 'css' => 'text/css', - 'doc' => 'application/msword', - 'dot' => 'application/msword', - 'dv' => 'video/x-dv', - 'dvi' => 'application/x-dvi', - 'eps' => 'application/postscript', - 'exe' => 'application/octet-stream', - 'gif' => 'image/gif', - 'gz' => 'application/x-gzip', - 'gzip' => 'application/x-gzip', - 'htm' => 'text/html', - 'html' => 'text/html', - 'ico' => 'image/x-icon', - 'jpe' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'js' => 'application/x-javascript', - 'log' => 'text/plain', - 'mid' => 'audio/x-midi', - 'mov' => 'video/quicktime', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg3', - 'mpg' => 'audio/mpeg', - 'pdf' => 'aplication/pdf', - 'png' => 'image/png', - 'rtf' => 'application/rtf', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'txt' => 'text/plain', - 'xml' => 'text/xml', - ); - - public static $defaultphp = array( - 'php' => true - ); - - public static $defaultphps = array( - 'phps' => true - ); - - public static $deny = array('/.+\.inc$/'); - - public static function viewSource($archive, $file) - { - // security, idea borrowed from PHK - if (!file_exists($archive . '.introspect')) { - header("HTTP/1.0 404 Not Found"); - return false; - } - if (self::_fileExists($archive, $_GET['viewsource'])) { - $source = highlight_file('phar://go-pear.phar/' . - $_GET['viewsource'], true); - header('Content-Type: text/html'); - header('Content-Length: ' . strlen($source)); - echo 'Source of ', - htmlspecialchars($_GET['viewsource']), ''; - echo '

Source of ', - htmlspecialchars($_GET['viewsource']), '

'; - if (isset($_GET['introspect'])) { - echo 'Return to ', htmlspecialchars($_GET['introspect']), '
'; - } - echo $source; - return false; - } else { - header("HTTP/1.0 404 Not Found"); - return false; - } - - } - - public static function introspect($archive, $dir) - { - // security, idea borrowed from PHK - if (!file_exists($archive . '.introspect')) { - header("HTTP/1.0 404 Not Found"); - return false; - } - if (!$dir) { - $dir = '/'; - } - $dir = self::processFile($dir); - if ($dir[0] != '/') { - $dir = '/' . $dir; - } - try { - $self = htmlspecialchars($_SERVER['PHP_SELF']); - $iterate = new DirectoryIterator('phar://go-pear.phar' . $dir); - echo 'Introspect ', htmlspecialchars($dir), - '

Introspect ', htmlspecialchars($dir), - '

    '; - if ($dir != '/') { - echo '
  • ..
  • '; - } - foreach ($iterate as $entry) { - if ($entry->isDot()) continue; - $name = self::processFile($entry->getPathname()); - $name = str_replace('phar://go-pear.phar/', '', $name); - if ($entry->isDir()) { - echo '
  • ', - htmlspecialchars($entry->getFilename()), '/ [directory]
  • '; - } else { - echo '
  • ', - htmlspecialchars($entry->getFilename()), '
  • '; - } - } - return false; - } catch (Exception $e) { - echo 'Directory not found: ', - htmlspecialchars($dir), '', - '

    Directory not found: ', htmlspecialchars($dir), '

    ', - '

    Try ', - 'This link

    '; - return false; - } - } - - public static function webFrontController($initfile) - { - if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) { - $uri = parse_url($_SERVER['REQUEST_URI']); - $archive = realpath($_SERVER['SCRIPT_FILENAME']); - $subpath = str_replace('/' . basename($archive), '', $uri['path']); - if (!$subpath || $subpath == '/') { - if (isset($_GET['viewsource'])) { - return self::viewSource($archive, $_GET['viewsource']); - } - if (isset($_GET['introspect'])) { - return self::introspect($archive, $_GET['introspect']); - } - $subpath = '/' . $initfile; - } - if (!self::_fileExists($archive, substr($subpath, 1))) { - header("HTTP/1.0 404 Not Found"); - return false; - } - foreach (self::$deny as $pattern) { - if (preg_match($pattern, $subpath)) { - header("HTTP/1.0 404 Not Found"); - return false; - } - } - $inf = pathinfo(basename($subpath)); - if (!isset($inf['extension'])) { - header('Content-Type: text/plain'); - header('Content-Length: ' . - self::_filesize($archive, substr($subpath, 1))); - readfile('phar://go-pear.phar' . $subpath); - return false; - } - if (isset(self::$defaultphp[$inf['extension']])) { - include 'phar://go-pear.phar' . $subpath; - return false; - } - if (isset(self::$defaultmimes[$inf['extension']])) { - header('Content-Type: ' . self::$defaultmimes[$inf['extension']]); - header('Content-Length: ' . - self::_filesize($archive, substr($subpath, 1))); - readfile('phar://go-pear.phar' . $subpath); - return false; - } - if (isset(self::$defaultphps[$inf['extension']])) { - header('Content-Type: text/html'); - $c = highlight_file('phar://go-pear.phar' . $subpath, true); - header('Content-Length: ' . strlen($c)); - echo $c; - return false; - } - header('Content-Type: text/plain'); - header('Content-Length: ' . - self::_filesize($archive, substr($subpath, 1))); - readfile('phar://go-pear.phar' . $subpath); - } - } - - /** - * Detect end of stub - * - * @param string $buffer stub past '__HALT_'.'COMPILER();' - * @return end of stub, prior to length of manifest. - */ - private static final function _endOfStubLength($buffer) - { - $pos = 0; - if (!strlen($buffer)) { - return $pos; - } - if (($buffer[0] == ' ' || $buffer[0] == "\n") && @substr($buffer, 1, 2) == '') - { - $pos += 3; - if ($buffer[$pos] == "\r" && $buffer[$pos+1] == "\n") { - $pos += 2; - } - else if ($buffer[$pos] == "\n") { - $pos += 1; - } - } - return $pos; - } - - /** - * Allows loading an external Phar archive without include()ing it - * - * @param string $file phar package to load - * @param string $alias alias to use - * @throws Exception - */ - public static final function loadPhar($file, $alias = NULL) - { - $file = realpath($file); - if ($file) { - $fp = fopen($file, 'rb'); - $buffer = ''; - while (!feof($fp)) { - $buffer .= fread($fp, 8192); - // don't break phars - if ($pos = strpos($buffer, '__HALT_COMPI' . 'LER();')) { - $buffer .= fread($fp, 5); - fclose($fp); - $pos += 18; - $pos += self::_endOfStubLength(substr($buffer, $pos)); - return self::_mapPhar($file, $pos, $alias); - } - } - fclose($fp); - } - } - - /** - * Map a full real file path to an alias used to refer to the .phar - * - * This function can only be called from the initialization of the .phar itself. - * Any attempt to call from outside the .phar or to re-alias the .phar will fail - * as a security measure. - * @param string $alias - * @param int $dataoffset the value of 42313 - */ - public static final function mapPhar($alias = NULL, $dataoffset = NULL) - { - try { - $trace = debug_backtrace(); - $file = $trace[0]['file']; - // this ensures that this is safe - if (!in_array($file, get_included_files())) { - die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' . - 'the phar that initiates it'); - } - $file = realpath($file); - if (!isset($dataoffset)) { - $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__'); - $fp = fopen($file, 'rb'); - fseek($fp, $dataoffset, SEEK_SET); - $dataoffset = $dataoffset + self::_endOfStubLength(fread($fp, 5)); - fclose($fp); - } - - self::_mapPhar($file, $dataoffset); - } catch (Exception $e) { - die($e->getMessage()); - } - } - - /** - * Sub-function, allows recovery from errors - * - * @param unknown_type $file - * @param unknown_type $dataoffset - */ - private static function _mapPhar($file, $dataoffset, $alias = NULL) - { - $file = realpath($file); - if (isset(self::$_manifest[$file])) { - return; - } - if (!is_array(self::$_pharMapping)) { - self::$_pharMapping = array(); - } - $fp = fopen($file, 'rb'); - // seek to __HALT_COMPILER_OFFSET__ - fseek($fp, $dataoffset); - $manifest_length = unpack('Vlen', fread($fp, 4)); - $manifest = ''; - $last = '1'; - while (strlen($last) && strlen($manifest) < $manifest_length['len']) { - $read = 8192; - if ($manifest_length['len'] - strlen($manifest) < 8192) { - $read = $manifest_length['len'] - strlen($manifest); - } - $last = fread($fp, $read); - $manifest .= $last; - } - if (strlen($manifest) < $manifest_length['len']) { - throw new Exception('ERROR: manifest length read was "' . - strlen($manifest) .'" should be "' . - $manifest_length['len'] . '"'); - } - $info = self::_unserializeManifest($manifest); - if ($info['alias']) { - $alias = $info['alias']; - $explicit = true; - } else { - if (!isset($alias)) { - $alias = $file; - } - $explicit = false; - } - self::$_manifest[$file] = $info['manifest']; - $compressed = $info['compressed']; - self::$_fileStart[$file] = ftell($fp); - fclose($fp); - if ($compressed & 0x00001000) { - if (!function_exists('gzinflate')) { - throw new Exception('Error: zlib extension is not enabled - gzinflate() function needed' . - ' for compressed .phars'); - } - } - if ($compressed & 0x00002000) { - if (!function_exists('bzdecompress')) { - throw new Exception('Error: bzip2 extension is not enabled - bzdecompress() function needed' . - ' for compressed .phars'); - } - } - if (isset(self::$_pharMapping[$alias])) { - throw new Exception('ERROR: PHP_Archive::mapPhar has already been called for alias "' . - $alias . '" cannot re-alias to "' . $file . '"'); - } - self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset, $explicit, - $info['metadata']); - self::$_pharFiles[$file] = $alias; - } - - /** - * extract the manifest into an internal array - * - * @param string $manifest - * @return false|array - */ - private static function _unserializeManifest($manifest) - { - // retrieve the number of files in the manifest - $info = unpack('V', substr($manifest, 0, 4)); - $apiver = substr($manifest, 4, 2); - $apiver = bin2hex($apiver); - $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]); - $majorcompat = hexdec($apiver[0]); - $calcapi = explode('.', self::APIVersion()); - if ($calcapi[0] != $majorcompat) { - throw new Exception('Phar is incompatible API version ' . $apiver_dots . ', but ' . - 'PHP_Archive is API version '.self::APIVersion()); - } - if ($calcapi[0] === '0') { - if (self::APIVersion() != $apiver_dots) { - throw new Exception('Phar is API version ' . $apiver_dots . - ', but PHP_Archive is API version '.self::APIVersion(), E_USER_ERROR); - } - } - $flags = unpack('V', substr($manifest, 6, 4)); - $ret = array('compressed' => $flags & 0x00003000); - // signature is not verified by default in PHP_Archive, phar is better - $ret['hassignature'] = $flags & 0x00010000; - $aliaslen = unpack('V', substr($manifest, 10, 4)); - if ($aliaslen) { - $ret['alias'] = substr($manifest, 14, $aliaslen[1]); - } else { - $ret['alias'] = false; - } - $manifest = substr($manifest, 14 + $aliaslen[1]); - $metadatalen = unpack('V', substr($manifest, 0, 4)); - if ($metadatalen[1]) { - $ret['metadata'] = unserialize(substr($manifest, 4, $metadatalen[1])); - $manifest = substr($manifest, 4 + $metadatalen[1]); - } else { - $ret['metadata'] = null; - $manifest = substr($manifest, 4); - } - $offset = 0; - $start = 0; - for ($i = 0; $i < $info[1]; $i++) { - // length of the file name - $len = unpack('V', substr($manifest, $start, 4)); - $start += 4; - // file name - $savepath = substr($manifest, $start, $len[1]); - $start += $len[1]; - // retrieve manifest data: - // 0 = uncompressed file size - // 1 = timestamp of when file was added to phar - // 2 = compressed filesize - // 3 = crc32 - // 4 = flags - // 5 = metadata length - $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($manifest, $start, 24))); - $ret['manifest'][$savepath][3] = sprintf('%u', $ret['manifest'][$savepath][3] - & 0xffffffff); - if ($ret['manifest'][$savepath][5]) { - $ret['manifest'][$savepath][6] = unserialize(substr($manifest, $start + 24, - $ret['manifest'][$savepath][5])); - } else { - $ret['manifest'][$savepath][6] = null; - } - $ret['manifest'][$savepath][7] = $offset; - $offset += $ret['manifest'][$savepath][2]; - $start += 24 + $ret['manifest'][$savepath][5]; - } - return $ret; - } - - /** - * @param string - */ - private static function processFile($path) - { - if ($path == '.') { - return ''; - } - $std = str_replace("\\", "/", $path); - while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ; - $std = str_replace("/./", "", $std); - if (strlen($std) > 1 && $std[0] == '/') { - $std = substr($std, 1); - } - if (strncmp($std, "./", 2) == 0) { - return substr($std, 2); - } else { - return $std; - } - } - - /** - * Seek in the master archive to a matching file or directory - * @param string - */ - protected function selectFile($path, $allowdirs = true) - { - $std = self::processFile($path); - if (isset(self::$_manifest[$this->_archiveName][$path])) { - $this->_setCurrentFile($path); - return true; - } - if (!$allowdirs) { - return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"'; - } - foreach (self::$_manifest[$this->_archiveName] as $file => $info) { - if (empty($std) || - //$std is a directory - strncmp($std.'/', $path, strlen($std)+1) == 0) { - $this->currentFilename = $this->internalFileLength = $this->currentStat = null; - return true; - } - } - return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"'; - } - - private function _setCurrentFile($path) - { - $this->currentStat = array( - 2 => 0100444, // file mode, readable by all, writeable by none - 4 => 0, // uid - 5 => 0, // gid - 7 => self::$_manifest[$this->_archiveName][$path][0], // size - 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time - ); - $this->currentFilename = $path; - $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2]; - // seek to offset of file header within the .phar - if (is_resource(@$this->fp)) { - fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][7]); - } - } - - private static function _fileExists($archive, $path) - { - return isset(self::$_manifest[$archive]) && - isset(self::$_manifest[$archive][$path]); - } - - private static function _filesize($archive, $path) - { - return self::$_manifest[$archive][$path][0]; - } - - /** - * Seek to a file within the master archive, and extract its contents - * @param string - * @return array|string an array containing an error message string is returned - * upon error, otherwise the file contents are returned - */ - public function extractFile($path) - { - $this->fp = @fopen($this->_archiveName, "rb"); - if (!$this->fp) { - return array('Error: cannot open phar "' . $this->_archiveName . '"'); - } - if (($e = $this->selectFile($path, false)) === true) { - $data = ''; - $count = $this->internalFileLength; - while ($count) { - if ($count < 8192) { - $data .= @fread($this->fp, $count); - $count = 0; - } else { - $count -= 8192; - $data .= @fread($this->fp, 8192); - } - } - @fclose($this->fp); - if (self::$_manifest[$this->_archiveName][$path][4] & self::GZ) { - $data = gzinflate($data); - } elseif (self::$_manifest[$this->_archiveName][$path][4] & self::BZ2) { - $data = bzdecompress($data); - } - if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) { - if (strlen($data) != $this->currentStat[7]) { - return array("Not valid internal .phar file (size error {$size} != " . - $this->currentStat[7] . ")"); - } - if (self::$_manifest[$this->_archiveName][$path][3] != sprintf("%u", crc32($data) & 0xffffffff)) { - return array("Not valid internal .phar file (checksum error)"); - } - self::$_manifest[$this->_archiveName][$path]['ok'] = true; - } - return $data; - } else { - @fclose($this->fp); - return array($e); - } - } - - /** - * Parse urls like phar:///fullpath/to/my.phar/file.txt - * - * @param string $file - * @return false|array - */ - static protected function parseUrl($file) - { - if (substr($file, 0, 7) != 'phar://') { - return false; - } - $file = substr($file, 7); - - $ret = array('scheme' => 'phar'); - $pos_p = strpos($file, '.phar.php'); - $pos_z = strpos($file, '.phar.gz'); - $pos_b = strpos($file, '.phar.bz2'); - if ($pos_p) { - if ($pos_z) { - return false; - } - $ret['host'] = substr($file, 0, $pos_p + strlen('.phar.php')); - $ret['path'] = substr($file, strlen($ret['host'])); - } elseif ($pos_z) { - $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.gz')); - $ret['path'] = substr($file, strlen($ret['host'])); - } elseif ($pos_b) { - $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.bz2')); - $ret['path'] = substr($file, strlen($ret['host'])); - } elseif (($pos_p = strpos($file, ".phar")) !== false) { - $ret['host'] = substr($file, 0, $pos_p + strlen('.phar')); - $ret['path'] = substr($file, strlen($ret['host'])); - } else { - return false; - } - if (!$ret['path']) { - $ret['path'] = '/'; - } - return $ret; - } - - /** - * Locate the .phar archive in the include_path and detect the file to open within - * the archive. - * - * Possible parameters are phar://pharname.phar/filename_within_phar.ext - * @param string a file within the archive - * @return string the filename within the .phar to retrieve - */ - public function initializeStream($file) - { - $file = self::processFile($file); - $info = @parse_url($file); - if (!$info) { - $info = self::parseUrl($file); - } - if (!$info) { - return false; - } - if (!isset($info['host'])) { - // malformed internal file - return false; - } - if (!isset(self::$_pharFiles[$info['host']]) && - !isset(self::$_pharMapping[$info['host']])) { - try { - self::loadPhar($info['host']); - // use alias from here out - $info['host'] = self::$_pharFiles[$info['host']]; - } catch (Exception $e) { - return false; - } - } - if (!isset($info['path'])) { - return false; - } elseif (strlen($info['path']) > 1) { - $info['path'] = substr($info['path'], 1); - } - if (isset(self::$_pharMapping[$info['host']])) { - $this->_basename = $info['host']; - $this->_archiveName = self::$_pharMapping[$info['host']][0]; - $this->_compressed = self::$_pharMapping[$info['host']][1]; - } elseif (isset(self::$_pharFiles[$info['host']])) { - $this->_archiveName = $info['host']; - $this->_basename = self::$_pharFiles[$info['host']]; - $this->_compressed = self::$_pharMapping[$this->_basename][1]; - } - $file = $info['path']; - return $file; - } - - /** - * Open the requested file - PHP streams API - * - * @param string $file String provided by the Stream wrapper - * @access private - */ - public function stream_open($file) - { - return $this->_streamOpen($file); - } - - /** - * @param string filename to opne, or directory name - * @param bool if true, a directory will be matched, otherwise only files - * will be matched - * @uses trigger_error() - * @return bool success of opening - * @access private - */ - private function _streamOpen($file, $searchForDir = false) - { - $path = $this->initializeStream($file); - if (!$path) { - trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR); - } - if (is_array($this->file = $this->extractFile($path))) { - trigger_error($this->file[0], E_USER_ERROR); - return false; - } - if ($path != $this->currentFilename) { - if (!$searchForDir) { - trigger_error("Cannot open '$file', is a directory", E_USER_ERROR); - return false; - } else { - $this->file = ''; - return true; - } - } - - if (!is_null($this->file) && $this->file !== false) { - return true; - } else { - return false; - } - } - - /** - * Read the data - PHP streams API - * - * @param int - * @access private - */ - public function stream_read($count) - { - $ret = substr($this->file, $this->position, $count); - $this->position += strlen($ret); - return $ret; - } - - /** - * Whether we've hit the end of the file - PHP streams API - * @access private - */ - function stream_eof() - { - return $this->position >= $this->currentStat[7]; - } - - /** - * For seeking the stream - PHP streams API - * @param int - * @param SEEK_SET|SEEK_CUR|SEEK_END - * @access private - */ - public function stream_seek($pos, $whence) - { - switch ($whence) { - case SEEK_SET: - if ($pos < 0) { - return false; - } - $this->position = $pos; - break; - case SEEK_CUR: - if ($pos + $this->currentStat[7] < 0) { - return false; - } - $this->position += $pos; - break; - case SEEK_END: - if ($pos + $this->currentStat[7] < 0) { - return false; - } - $this->position = $pos + $this->currentStat[7]; - break; - default: - return false; - } - return true; - } - - /** - * The current position in the stream - PHP streams API - * @access private - */ - public function stream_tell() - { - return $this->position; - } - - /** - * The result of an fstat call, returns mod time from creation, and file size - - * PHP streams API - * @uses _stream_stat() - * @access private - */ - public function stream_stat() - { - return $this->_stream_stat(); - } - - /** - * Retrieve statistics on a file or directory within the .phar - * @param string file/directory to stat - * @access private - */ - public function _stream_stat($file = null) - { - $std = $file ? self::processFile($file) : $this->currentFilename; - if ($file) { - if (isset(self::$_manifest[$this->_archiveName][$file])) { - $this->_setCurrentFile($file); - $isdir = false; - } else { - do { - $isdir = false; - if ($file == '/') { - break; - } - foreach (self::$_manifest[$this->_archiveName] as $path => $info) { - if (strpos($path, $file) === 0) { - if (strlen($path) > strlen($file) && - $path[strlen($file)] == '/') { - break 2; - } - } - } - // no files exist and no directories match this string - return false; - } while (false); - $isdir = true; - } - } else { - $isdir = false; // open streams must be files - } - $mode = $isdir ? 0040444 : 0100444; - // 040000 = dir, 010000 = file - // everything is readable, nothing is writeable - return array( - 0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices - 'dev' => 0, 'ino' => 0, - 'mode' => $mode, - 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0, - 'size' => $this->currentStat[7], - 'atime' => $this->currentStat[9], - 'mtime' => $this->currentStat[9], - 'ctime' => $this->currentStat[9], - ); - } - - /** - * Stat a closed file or directory - PHP streams API - * @param string - * @param int - * @access private - */ - public function url_stat($url, $flags) - { - $path = $this->initializeStream($url); - return $this->_stream_stat($path); - } - - /** - * Open a directory in the .phar for reading - PHP streams API - * @param string directory name - * @access private - */ - public function dir_opendir($path) - { - $info = @parse_url($path); - if (!$info) { - $info = self::parseUrl($path); - if (!$info) { - trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir', - E_USER_ERROR); - return false; - } - } - $path = !empty($info['path']) ? - $info['host'] . $info['path'] : $info['host'] . '/'; - $path = $this->initializeStream('phar://' . $path); - if (isset(self::$_manifest[$this->_archiveName][$path])) { - trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir', - E_USER_ERROR); - return false; - } - if ($path == false) { - trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR); - return false; - } - $this->fp = @fopen($this->_archiveName, "rb"); - if (!$this->fp) { - trigger_error('Error: cannot open phar "' . $this->_archiveName . '"'); - return false; - } - $this->_dirFiles = array(); - foreach (self::$_manifest[$this->_archiveName] as $file => $info) { - if ($path == '/') { - if (strpos($file, '/')) { - $a = explode('/', $file); - $this->_dirFiles[array_shift($a)] = true; - } else { - $this->_dirFiles[$file] = true; - } - } elseif (strpos($file, $path) === 0) { - $fname = substr($file, strlen($path) + 1); - if (strpos($fname, '/')) { - // this is a directory - $a = explode('/', $fname); - $this->_dirFiles[array_shift($a)] = true; - } elseif ($file[strlen($path)] == '/') { - // this is a file - $this->_dirFiles[$fname] = true; - } - } - } - @fclose($this->fp); - if (!count($this->_dirFiles)) { - return false; - } - @uksort($this->_dirFiles, 'strnatcmp'); - return true; - } - - /** - * Read the next directory entry - PHP streams API - * @access private - */ - public function dir_readdir() - { - $ret = key($this->_dirFiles); - @next($this->_dirFiles); - if (!$ret) { - return false; - } - return $ret; - } - - /** - * Close a directory handle opened with opendir() - PHP streams API - * @access private - */ - public function dir_closedir() - { - $this->_dirFiles = array(); - return true; - } - - /** - * Rewind to the first directory entry - PHP streams API - * @access private - */ - public function dir_rewinddir() - { - @reset($this->_dirFiles); - return true; - } - - /** - * API version of this class - * @return string - */ - public static final function APIVersion() - { - return '1.0.0'; - } - - /** - * Retrieve Phar-specific metadata for a Phar archive - * - * @param string $phar full path to Phar archive, or alias - * @return null|mixed The value that was serialized for the Phar - * archive's metadata - * @throws Exception - */ - public static function getPharMetadata($phar) - { - if (isset(self::$_pharFiles[$phar])) { - $phar = self::$_pharFiles[$phar]; - } - if (!isset(self::$_pharMapping[$phar])) { - throw new Exception('Unknown Phar archive: "' . $phar . '"'); - } - return self::$_pharMapping[$phar][4]; - } - - /** - * Retrieve File-specific metadata for a Phar archive file - * - * @param string $phar full path to Phar archive, or alias - * @param string $file relative path to file within Phar archive - * @return null|mixed The value that was serialized for the Phar - * archive's metadata - * @throws Exception - */ - public static function getFileMetadata($phar, $file) - { - if (!isset(self::$_pharFiles[$phar])) { - if (!isset(self::$_pharMapping[$phar])) { - throw new Exception('Unknown Phar archive: "' . $phar . '"'); - } - $phar = self::$_pharMapping[$phar][0]; - } - if (!isset(self::$_manifest[$phar])) { - throw new Exception('Unknown Phar: "' . $phar . '"'); - } - $file = self::processFile($file); - if (!isset(self::$_manifest[$phar][$file])) { - throw new Exception('Unknown file "' . $file . '" within Phar "'. $phar . '"'); - } - return self::$_manifest[$phar][$file][6]; - } - - /** - * @return list of supported signature algorithmns. - */ - public static function getsupportedsignatures() - { - $ret = array('MD5', 'SHA-1'); - if (extension_loaded('hash')) { - $ret[] = 'SHA-256'; - $ret[] = 'SHA-512'; - } - return $ret; - } -}} -if (!class_exists('Phar')) { - PHP_Archive::mapPhar(null, 42313 ); -} else { - try { - Phar::mapPhar(); - } catch (Exception $e) { - echo $e->getMessage(); - } -} -if (class_exists('PHP_Archive') && !in_array('phar', stream_get_wrappers())) { - stream_wrapper_register('phar', 'PHP_Archive'); -} - -@ini_set('memory_limit', -1); -if (extension_loaded('phar')) {if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) { - $uri = parse_url($_SERVER['REQUEST_URI']); - $archive = realpath($_SERVER['SCRIPT_FILENAME']); - $subpath = str_replace('/' . basename($archive), '', $uri['path']); - $mimetypes = array ( - 'aif' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'arc' => 'application/octet-stream', - 'arj' => 'application/octet-stream', - 'art' => 'image/x-jg', - 'asf' => 'video/x-ms-asf', - 'asx' => 'video/x-ms-asf', - 'avi' => 'video/avi', - 'bin' => 'application/octet-stream', - 'bm' => 'image/bmp', - 'bmp' => 'image/bmp', - 'bz2' => 'application/x-bzip2', - 'css' => 'text/css', - 'doc' => 'application/msword', - 'dot' => 'application/msword', - 'dv' => 'video/x-dv', - 'dvi' => 'application/x-dvi', - 'eps' => 'application/postscript', - 'exe' => 'application/octet-stream', - 'gif' => 'image/gif', - 'gz' => 'application/x-gzip', - 'gzip' => 'application/x-gzip', - 'htm' => 'text/html', - 'html' => 'text/html', - 'ico' => 'image/x-icon', - 'jpe' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'js' => 'application/x-javascript', - 'log' => 'text/plain', - 'mid' => 'audio/x-midi', - 'mov' => 'video/quicktime', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg3', - 'mpg' => 'audio/mpeg', - 'pdf' => 'aplication/pdf', - 'png' => 'image/png', - 'rtf' => 'application/rtf', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'txt' => 'text/plain', - 'xml' => 'text/xml', -); - $phpfiles = array ( - 'php' => true, -); - $phpsfiles = array ( - 'phps' => true, -); - $deny = array ( - 0 => '/.+\\.inc$/', -); - $subpath = str_replace('/' . basename($archive), '', $uri['path']); - if (!$subpath || $subpath == '/') { - $subpath = '/PEAR.php'; - } - if ($subpath[0] != '/') { - $subpath = '/' . $subpath; - } - if (!@file_exists('phar://' . $archive . $subpath)) { - header("HTTP/1.0 404 Not Found"); - exit; - } - - foreach ($deny as $pattern) { - if (preg_match($pattern, $subpath)) { - header("HTTP/1.0 404 Not Found"); - exit; - } - } - $inf = pathinfo(basename($subpath)); - if (!isset($inf['extension'])) { - header('Content-Type: text/plain'); - header('Content-Length: ' . filesize('phar://' . $archive . $subpath)); - readfile('phar://' . $archive . $subpath); - exit; - } - if (isset($phpfiles[$inf['extension']])) { - include 'phar://' . $archive . '/' . $subpath; - exit; - } - if (isset($mimetypes[$inf['extension']])) { - header('Content-Type: ' . $mimetypes[$inf['extension']]); - header('Content-Length: ' . filesize('phar://' . $archive . $subpath)); - readfile('phar://' . $archive . $subpath); - exit; - } - if (isset($phpsfiles[$inf['extension']])) { - header('Content-Type: text/html'); - $c = highlight_file('phar://' . $archive . $subpath, true); - header('Content-Length: ' . strlen($c)); - echo $c; - exit; - } - header('Content-Type: text/plain'); - header('Content-Length: ' . filesize('phar://' . $archive . '/' . $subpath)); - readfile('phar://' . $archive . '/' . $subpath); - exit; -}} else {if (!empty($_SERVER['REQUEST_URI'])) {PHP_Archive::webFrontController('PEAR.php');exit;}} - - - -require_once 'phar://go-pear.phar/index.php'; -__HALT_COMPILER();aF go-pear.pharArchive/Tar.phpýõ/£JýõXÇgÛmConsole/Getopt.phpS2/£JS2 - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * @category File_Formats - * @package Archive_Tar - * @author Vincent Blavet - * @copyright 1997-2008 The Authors - * @license http://www.opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Tar.php 287963 2009-09-02 08:18:55Z mrook $ - * @link http://pear.php.net/package/Archive_Tar - */ - -require_once 'phar://go-pear.phar/' . 'PEAR.php'; - - -define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001); -define ('ARCHIVE_TAR_END_BLOCK', pack("a512", '')); - -/** -* Creates a (compressed) Tar archive -* -* @author Vincent Blavet -* @version $Revision: 287963 $ -* @license http://www.opensource.org/licenses/bsd-license.php New BSD License -* @package Archive_Tar -*/ -class Archive_Tar extends PEAR -{ - /** - * @var string Name of the Tar - */ - var $_tarname=''; - - /** - * @var boolean if true, the Tar file will be gzipped - */ - var $_compress=false; - - /** - * @var string Type of compression : 'none', 'gz' or 'bz2' - */ - var $_compress_type='none'; - - /** - * @var string Explode separator - */ - var $_separator=' '; - - /** - * @var file descriptor - */ - var $_file=0; - - /** - * @var string Local Tar name of a remote Tar (http:// or ftp://) - */ - var $_temp_tarname=''; - - // {{{ constructor - /** - * Archive_Tar Class constructor. This flavour of the constructor only - * declare a new Archive_Tar object, identifying it by the name of the - * tar file. - * If the compress argument is set the tar will be read or created as a - * gzip or bz2 compressed TAR file. - * - * @param string $p_tarname The name of the tar archive to create - * @param string $p_compress can be null, 'gz' or 'bz2'. This - * parameter indicates if gzip or bz2 compression - * is required. For compatibility reason the - * boolean value 'true' means 'gz'. - * @access public - */ - function Archive_Tar($p_tarname, $p_compress = null) - { - $this->PEAR(); - $this->_compress = false; - $this->_compress_type = 'none'; - if (($p_compress === null) || ($p_compress == '')) { - if (@file_exists($p_tarname)) { - if ($fp = @fopen($p_tarname, "rb")) { - // look for gzip magic cookie - $data = fread($fp, 2); - fclose($fp); - if ($data == "\37\213") { - $this->_compress = true; - $this->_compress_type = 'gz'; - // No sure it's enought for a magic code .... - } elseif ($data == "BZ") { - $this->_compress = true; - $this->_compress_type = 'bz2'; - } - } - } else { - // probably a remote file or some file accessible - // through a stream interface - if (substr($p_tarname, -2) == 'gz') { - $this->_compress = true; - $this->_compress_type = 'gz'; - } elseif ((substr($p_tarname, -3) == 'bz2') || - (substr($p_tarname, -2) == 'bz')) { - $this->_compress = true; - $this->_compress_type = 'bz2'; - } - } - } else { - if (($p_compress === true) || ($p_compress == 'gz')) { - $this->_compress = true; - $this->_compress_type = 'gz'; - } else if ($p_compress == 'bz2') { - $this->_compress = true; - $this->_compress_type = 'bz2'; - } else { - $this->_error("Unsupported compression type '$p_compress'\n". - "Supported types are 'gz' and 'bz2'.\n"); - return false; - } - } - $this->_tarname = $p_tarname; - if ($this->_compress) { // assert zlib or bz2 extension support - if ($this->_compress_type == 'gz') - $extname = 'zlib'; - else if ($this->_compress_type == 'bz2') - $extname = 'bz2'; - - if (!extension_loaded($extname)) { - PEAR::loadExtension($extname); - } - if (!extension_loaded($extname)) { - $this->_error("The extension '$extname' couldn't be found.\n". - "Please make sure your version of PHP was built ". - "with '$extname' support.\n"); - return false; - } - } - } - // }}} - - // {{{ destructor - function _Archive_Tar() - { - $this->_close(); - // ----- Look for a local copy to delete - if ($this->_temp_tarname != '') - @unlink($this->_temp_tarname); - $this->_PEAR(); - } - // }}} - - // {{{ create() - /** - * This method creates the archive file and add the files / directories - * that are listed in $p_filelist. - * If a file with the same name exist and is writable, it is replaced - * by the new tar. - * The method return false and a PEAR error text. - * The $p_filelist parameter can be an array of string, each string - * representing a filename or a directory name with their path if - * needed. It can also be a single string with names separated by a - * single blank. - * For each directory added in the archive, the files and - * sub-directories are also added. - * See also createModify() method for more details. - * - * @param array $p_filelist An array of filenames and directory names, or a - * single string with names separated by a single - * blank space. - * @return true on success, false on error. - * @see createModify() - * @access public - */ - function create($p_filelist) - { - return $this->createModify($p_filelist, '', ''); - } - // }}} - - // {{{ add() - /** - * This method add the files / directories that are listed in $p_filelist in - * the archive. If the archive does not exist it is created. - * The method return false and a PEAR error text. - * The files and directories listed are only added at the end of the archive, - * even if a file with the same name is already archived. - * See also createModify() method for more details. - * - * @param array $p_filelist An array of filenames and directory names, or a - * single string with names separated by a single - * blank space. - * @return true on success, false on error. - * @see createModify() - * @access public - */ - function add($p_filelist) - { - return $this->addModify($p_filelist, '', ''); - } - // }}} - - // {{{ extract() - function extract($p_path='') - { - return $this->extractModify($p_path, ''); - } - // }}} - - // {{{ listContent() - function listContent() - { - $v_list_detail = array(); - - if ($this->_openRead()) { - if (!$this->_extractList('', $v_list_detail, "list", '', '')) { - unset($v_list_detail); - $v_list_detail = 0; - } - $this->_close(); - } - - return $v_list_detail; - } - // }}} - - // {{{ createModify() - /** - * This method creates the archive file and add the files / directories - * that are listed in $p_filelist. - * If the file already exists and is writable, it is replaced by the - * new tar. It is a create and not an add. If the file exists and is - * read-only or is a directory it is not replaced. The method return - * false and a PEAR error text. - * The $p_filelist parameter can be an array of string, each string - * representing a filename or a directory name with their path if - * needed. It can also be a single string with names separated by a - * single blank. - * The path indicated in $p_remove_dir will be removed from the - * memorized path of each file / directory listed when this path - * exists. By default nothing is removed (empty path '') - * The path indicated in $p_add_dir will be added at the beginning of - * the memorized path of each file / directory listed. However it can - * be set to empty ''. The adding of a path is done after the removing - * of path. - * The path add/remove ability enables the user to prepare an archive - * for extraction in a different path than the origin files are. - * See also addModify() method for file adding properties. - * - * @param array $p_filelist An array of filenames and directory names, - * or a single string with names separated by - * a single blank space. - * @param string $p_add_dir A string which contains a path to be added - * to the memorized path of each element in - * the list. - * @param string $p_remove_dir A string which contains a path to be - * removed from the memorized path of each - * element in the list, when relevant. - * @return boolean true on success, false on error. - * @access public - * @see addModify() - */ - function createModify($p_filelist, $p_add_dir, $p_remove_dir='') - { - $v_result = true; - - if (!$this->_openWrite()) - return false; - - if ($p_filelist != '') { - if (is_array($p_filelist)) - $v_list = $p_filelist; - elseif (is_string($p_filelist)) - $v_list = explode($this->_separator, $p_filelist); - else { - $this->_cleanFile(); - $this->_error('Invalid file list'); - return false; - } - - $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir); - } - - if ($v_result) { - $this->_writeFooter(); - $this->_close(); - } else - $this->_cleanFile(); - - return $v_result; - } - // }}} - - // {{{ addModify() - /** - * This method add the files / directories listed in $p_filelist at the - * end of the existing archive. If the archive does not yet exists it - * is created. - * The $p_filelist parameter can be an array of string, each string - * representing a filename or a directory name with their path if - * needed. It can also be a single string with names separated by a - * single blank. - * The path indicated in $p_remove_dir will be removed from the - * memorized path of each file / directory listed when this path - * exists. By default nothing is removed (empty path '') - * The path indicated in $p_add_dir will be added at the beginning of - * the memorized path of each file / directory listed. However it can - * be set to empty ''. The adding of a path is done after the removing - * of path. - * The path add/remove ability enables the user to prepare an archive - * for extraction in a different path than the origin files are. - * If a file/dir is already in the archive it will only be added at the - * end of the archive. There is no update of the existing archived - * file/dir. However while extracting the archive, the last file will - * replace the first one. This results in a none optimization of the - * archive size. - * If a file/dir does not exist the file/dir is ignored. However an - * error text is send to PEAR error. - * If a file/dir is not readable the file/dir is ignored. However an - * error text is send to PEAR error. - * - * @param array $p_filelist An array of filenames and directory - * names, or a single string with names - * separated by a single blank space. - * @param string $p_add_dir A string which contains a path to be - * added to the memorized path of each - * element in the list. - * @param string $p_remove_dir A string which contains a path to be - * removed from the memorized path of - * each element in the list, when - * relevant. - * @return true on success, false on error. - * @access public - */ - function addModify($p_filelist, $p_add_dir, $p_remove_dir='') - { - $v_result = true; - - if (!$this->_isArchive()) - $v_result = $this->createModify($p_filelist, $p_add_dir, - $p_remove_dir); - else { - if (is_array($p_filelist)) - $v_list = $p_filelist; - elseif (is_string($p_filelist)) - $v_list = explode($this->_separator, $p_filelist); - else { - $this->_error('Invalid file list'); - return false; - } - - $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir); - } - - return $v_result; - } - // }}} - - // {{{ addString() - /** - * This method add a single string as a file at the - * end of the existing archive. If the archive does not yet exists it - * is created. - * - * @param string $p_filename A string which contains the full - * filename path that will be associated - * with the string. - * @param string $p_string The content of the file added in - * the archive. - * @return true on success, false on error. - * @access public - */ - function addString($p_filename, $p_string) - { - $v_result = true; - - if (!$this->_isArchive()) { - if (!$this->_openWrite()) { - return false; - } - $this->_close(); - } - - if (!$this->_openAppend()) - return false; - - // Need to check the get back to the temporary file ? .... - $v_result = $this->_addString($p_filename, $p_string); - - $this->_writeFooter(); - - $this->_close(); - - return $v_result; - } - // }}} - - // {{{ extractModify() - /** - * This method extract all the content of the archive in the directory - * indicated by $p_path. When relevant the memorized path of the - * files/dir can be modified by removing the $p_remove_path path at the - * beginning of the file/dir path. - * While extracting a file, if the directory path does not exists it is - * created. - * While extracting a file, if the file already exists it is replaced - * without looking for last modification date. - * While extracting a file, if the file already exists and is write - * protected, the extraction is aborted. - * While extracting a file, if a directory with the same name already - * exists, the extraction is aborted. - * While extracting a directory, if a file with the same name already - * exists, the extraction is aborted. - * While extracting a file/directory if the destination directory exist - * and is write protected, or does not exist but can not be created, - * the extraction is aborted. - * If after extraction an extracted file does not show the correct - * stored file size, the extraction is aborted. - * When the extraction is aborted, a PEAR error text is set and false - * is returned. However the result can be a partial extraction that may - * need to be manually cleaned. - * - * @param string $p_path The path of the directory where the - * files/dir need to by extracted. - * @param string $p_remove_path Part of the memorized path that can be - * removed if present at the beginning of - * the file/dir path. - * @return boolean true on success, false on error. - * @access public - * @see extractList() - */ - function extractModify($p_path, $p_remove_path) - { - $v_result = true; - $v_list_detail = array(); - - if ($v_result = $this->_openRead()) { - $v_result = $this->_extractList($p_path, $v_list_detail, - "complete", 0, $p_remove_path); - $this->_close(); - } - - return $v_result; - } - // }}} - - // {{{ extractInString() - /** - * This method extract from the archive one file identified by $p_filename. - * The return value is a string with the file content, or NULL on error. - * @param string $p_filename The path of the file to extract in a string. - * @return a string with the file content or NULL. - * @access public - */ - function extractInString($p_filename) - { - if ($this->_openRead()) { - $v_result = $this->_extractInString($p_filename); - $this->_close(); - } else { - $v_result = NULL; - } - - return $v_result; - } - // }}} - - // {{{ extractList() - /** - * This method extract from the archive only the files indicated in the - * $p_filelist. These files are extracted in the current directory or - * in the directory indicated by the optional $p_path parameter. - * If indicated the $p_remove_path can be used in the same way as it is - * used in extractModify() method. - * @param array $p_filelist An array of filenames and directory names, - * or a single string with names separated - * by a single blank space. - * @param string $p_path The path of the directory where the - * files/dir need to by extracted. - * @param string $p_remove_path Part of the memorized path that can be - * removed if present at the beginning of - * the file/dir path. - * @return true on success, false on error. - * @access public - * @see extractModify() - */ - function extractList($p_filelist, $p_path='', $p_remove_path='') - { - $v_result = true; - $v_list_detail = array(); - - if (is_array($p_filelist)) - $v_list = $p_filelist; - elseif (is_string($p_filelist)) - $v_list = explode($this->_separator, $p_filelist); - else { - $this->_error('Invalid string list'); - return false; - } - - if ($v_result = $this->_openRead()) { - $v_result = $this->_extractList($p_path, $v_list_detail, "partial", - $v_list, $p_remove_path); - $this->_close(); - } - - return $v_result; - } - // }}} - - // {{{ setAttribute() - /** - * This method set specific attributes of the archive. It uses a variable - * list of parameters, in the format attribute code + attribute values : - * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ','); - * @param mixed $argv variable list of attributes and values - * @return true on success, false on error. - * @access public - */ - function setAttribute() - { - $v_result = true; - - // ----- Get the number of variable list of arguments - if (($v_size = func_num_args()) == 0) { - return true; - } - - // ----- Get the arguments - $v_att_list = &func_get_args(); - - // ----- Read the attributes - $i=0; - while ($i<$v_size) { - - // ----- Look for next option - switch ($v_att_list[$i]) { - // ----- Look for options that request a string value - case ARCHIVE_TAR_ATT_SEPARATOR : - // ----- Check the number of parameters - if (($i+1) >= $v_size) { - $this->_error('Invalid number of parameters for ' - .'attribute ARCHIVE_TAR_ATT_SEPARATOR'); - return false; - } - - // ----- Get the value - $this->_separator = $v_att_list[$i+1]; - $i++; - break; - - default : - $this->_error('Unknow attribute code '.$v_att_list[$i].''); - return false; - } - - // ----- Next attribute - $i++; - } - - return $v_result; - } - // }}} - - // {{{ _error() - function _error($p_message) - { - // ----- To be completed - $this->raiseError($p_message); - } - // }}} - - // {{{ _warning() - function _warning($p_message) - { - // ----- To be completed - $this->raiseError($p_message); - } - // }}} - - // {{{ _isArchive() - function _isArchive($p_filename=NULL) - { - if ($p_filename == NULL) { - $p_filename = $this->_tarname; - } - clearstatcache(); - return @is_file($p_filename) && !@is_link($p_filename); - } - // }}} - - // {{{ _openWrite() - function _openWrite() - { - if ($this->_compress_type == 'gz') - $this->_file = @gzopen($this->_tarname, "wb9"); - else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($this->_tarname, "w"); - else if ($this->_compress_type == 'none') - $this->_file = @fopen($this->_tarname, "wb"); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - if ($this->_file == 0) { - $this->_error('Unable to open in write mode \'' - .$this->_tarname.'\''); - return false; - } - - return true; - } - // }}} - - // {{{ _openRead() - function _openRead() - { - if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') { - - // ----- Look if a local copy need to be done - if ($this->_temp_tarname == '') { - $this->_temp_tarname = uniqid('tar').'.tmp'; - if (!$v_file_from = @fopen($this->_tarname, 'rb')) { - $this->_error('Unable to open in read mode \'' - .$this->_tarname.'\''); - $this->_temp_tarname = ''; - return false; - } - if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) { - $this->_error('Unable to open in write mode \'' - .$this->_temp_tarname.'\''); - $this->_temp_tarname = ''; - return false; - } - while ($v_data = @fread($v_file_from, 1024)) - @fwrite($v_file_to, $v_data); - @fclose($v_file_from); - @fclose($v_file_to); - } - - // ----- File to open if the local copy - $v_filename = $this->_temp_tarname; - - } else - // ----- File to open if the normal Tar file - $v_filename = $this->_tarname; - - if ($this->_compress_type == 'gz') - $this->_file = @gzopen($v_filename, "rb"); - else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($v_filename, "r"); - else if ($this->_compress_type == 'none') - $this->_file = @fopen($v_filename, "rb"); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - if ($this->_file == 0) { - $this->_error('Unable to open in read mode \''.$v_filename.'\''); - return false; - } - - return true; - } - // }}} - - // {{{ _openReadWrite() - function _openReadWrite() - { - if ($this->_compress_type == 'gz') - $this->_file = @gzopen($this->_tarname, "r+b"); - else if ($this->_compress_type == 'bz2') { - $this->_error('Unable to open bz2 in read/write mode \'' - .$this->_tarname.'\' (limitation of bz2 extension)'); - return false; - } else if ($this->_compress_type == 'none') - $this->_file = @fopen($this->_tarname, "r+b"); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - if ($this->_file == 0) { - $this->_error('Unable to open in read/write mode \'' - .$this->_tarname.'\''); - return false; - } - - return true; - } - // }}} - - // {{{ _close() - function _close() - { - //if (isset($this->_file)) { - if (is_resource($this->_file)) { - if ($this->_compress_type == 'gz') - @gzclose($this->_file); - else if ($this->_compress_type == 'bz2') - @bzclose($this->_file); - else if ($this->_compress_type == 'none') - @fclose($this->_file); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - $this->_file = 0; - } - - // ----- Look if a local copy need to be erase - // Note that it might be interesting to keep the url for a time : ToDo - if ($this->_temp_tarname != '') { - @unlink($this->_temp_tarname); - $this->_temp_tarname = ''; - } - - return true; - } - // }}} - - // {{{ _cleanFile() - function _cleanFile() - { - $this->_close(); - - // ----- Look for a local copy - if ($this->_temp_tarname != '') { - // ----- Remove the local copy but not the remote tarname - @unlink($this->_temp_tarname); - $this->_temp_tarname = ''; - } else { - // ----- Remove the local tarname file - @unlink($this->_tarname); - } - $this->_tarname = ''; - - return true; - } - // }}} - - // {{{ _writeBlock() - function _writeBlock($p_binary_data, $p_len=null) - { - if (is_resource($this->_file)) { - if ($p_len === null) { - if ($this->_compress_type == 'gz') - @gzputs($this->_file, $p_binary_data); - else if ($this->_compress_type == 'bz2') - @bzwrite($this->_file, $p_binary_data); - else if ($this->_compress_type == 'none') - @fputs($this->_file, $p_binary_data); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - } else { - if ($this->_compress_type == 'gz') - @gzputs($this->_file, $p_binary_data, $p_len); - else if ($this->_compress_type == 'bz2') - @bzwrite($this->_file, $p_binary_data, $p_len); - else if ($this->_compress_type == 'none') - @fputs($this->_file, $p_binary_data, $p_len); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - } - } - return true; - } - // }}} - - // {{{ _readBlock() - function _readBlock() - { - $v_block = null; - if (is_resource($this->_file)) { - if ($this->_compress_type == 'gz') - $v_block = @gzread($this->_file, 512); - else if ($this->_compress_type == 'bz2') - $v_block = @bzread($this->_file, 512); - else if ($this->_compress_type == 'none') - $v_block = @fread($this->_file, 512); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - } - return $v_block; - } - // }}} - - // {{{ _jumpBlock() - function _jumpBlock($p_len=null) - { - if (is_resource($this->_file)) { - if ($p_len === null) - $p_len = 1; - - if ($this->_compress_type == 'gz') { - @gzseek($this->_file, gztell($this->_file)+($p_len*512)); - } - else if ($this->_compress_type == 'bz2') { - // ----- Replace missing bztell() and bzseek() - for ($i=0; $i<$p_len; $i++) - $this->_readBlock(); - } else if ($this->_compress_type == 'none') - @fseek($this->_file, ftell($this->_file)+($p_len*512)); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - } - return true; - } - // }}} - - // {{{ _writeFooter() - function _writeFooter() - { - if (is_resource($this->_file)) { - // ----- Write the last 0 filled block for end of archive - $v_binary_data = pack('a1024', ''); - $this->_writeBlock($v_binary_data); - } - return true; - } - // }}} - - // {{{ _addList() - function _addList($p_list, $p_add_dir, $p_remove_dir) - { - $v_result=true; - $v_header = array(); - - // ----- Remove potential windows directory separator - $p_add_dir = $this->_translateWinPath($p_add_dir); - $p_remove_dir = $this->_translateWinPath($p_remove_dir, false); - - if (!$this->_file) { - $this->_error('Invalid file descriptor'); - return false; - } - - if (sizeof($p_list) == 0) - return true; - - foreach ($p_list as $v_filename) { - if (!$v_result) { - break; - } - - // ----- Skip the current tar name - if ($v_filename == $this->_tarname) - continue; - - if ($v_filename == '') - continue; - - if (!file_exists($v_filename)) { - $this->_warning("File '$v_filename' does not exist"); - continue; - } - - // ----- Add the file or directory header - if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) - return false; - - if (@is_dir($v_filename) && !@is_link($v_filename)) { - if (!($p_hdir = opendir($v_filename))) { - $this->_warning("Directory '$v_filename' can not be read"); - continue; - } - while (false !== ($p_hitem = readdir($p_hdir))) { - if (($p_hitem != '.') && ($p_hitem != '..')) { - if ($v_filename != ".") - $p_temp_list[0] = $v_filename.'/'.$p_hitem; - else - $p_temp_list[0] = $p_hitem; - - $v_result = $this->_addList($p_temp_list, - $p_add_dir, - $p_remove_dir); - } - } - - unset($p_temp_list); - unset($p_hdir); - unset($p_hitem); - } - } - - return $v_result; - } - // }}} - - // {{{ _addFile() - function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir) - { - if (!$this->_file) { - $this->_error('Invalid file descriptor'); - return false; - } - - if ($p_filename == '') { - $this->_error('Invalid file name'); - return false; - } - - // ----- Calculate the stored filename - $p_filename = $this->_translateWinPath($p_filename, false);; - $v_stored_filename = $p_filename; - if (strcmp($p_filename, $p_remove_dir) == 0) { - return true; - } - if ($p_remove_dir != '') { - if (substr($p_remove_dir, -1) != '/') - $p_remove_dir .= '/'; - - if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) - $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); - } - $v_stored_filename = $this->_translateWinPath($v_stored_filename); - if ($p_add_dir != '') { - if (substr($p_add_dir, -1) == '/') - $v_stored_filename = $p_add_dir.$v_stored_filename; - else - $v_stored_filename = $p_add_dir.'/'.$v_stored_filename; - } - - $v_stored_filename = $this->_pathReduction($v_stored_filename); - - if ($this->_isArchive($p_filename)) { - if (($v_file = @fopen($p_filename, "rb")) == 0) { - $this->_warning("Unable to open file '".$p_filename - ."' in binary read mode"); - return true; - } - - if (!$this->_writeHeader($p_filename, $v_stored_filename)) - return false; - - while (($v_buffer = fread($v_file, 512)) != '') { - $v_binary_data = pack("a512", "$v_buffer"); - $this->_writeBlock($v_binary_data); - } - - fclose($v_file); - - } else { - // ----- Only header for dir - if (!$this->_writeHeader($p_filename, $v_stored_filename)) - return false; - } - - return true; - } - // }}} - - // {{{ _addString() - function _addString($p_filename, $p_string) - { - if (!$this->_file) { - $this->_error('Invalid file descriptor'); - return false; - } - - if ($p_filename == '') { - $this->_error('Invalid file name'); - return false; - } - - // ----- Calculate the stored filename - $p_filename = $this->_translateWinPath($p_filename, false);; - - if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), - time(), 384, "", 0, 0)) - return false; - - $i=0; - while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') { - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - } - - return true; - } - // }}} - - // {{{ _writeHeader() - function _writeHeader($p_filename, $p_stored_filename) - { - if ($p_stored_filename == '') - $p_stored_filename = $p_filename; - $v_reduce_filename = $this->_pathReduction($p_stored_filename); - - if (strlen($v_reduce_filename) > 99) { - if (!$this->_writeLongHeader($v_reduce_filename)) - return false; - } - - $v_info = lstat($p_filename); - $v_uid = sprintf("%07s", DecOct($v_info[4])); - $v_gid = sprintf("%07s", DecOct($v_info[5])); - $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777)); - - $v_mtime = sprintf("%011s", DecOct($v_info['mtime'])); - - $v_linkname = ''; - - if (@is_link($p_filename)) { - $v_typeflag = '2'; - $v_linkname = readlink($p_filename); - $v_size = sprintf("%011s", DecOct(0)); - } elseif (@is_dir($p_filename)) { - $v_typeflag = "5"; - $v_size = sprintf("%011s", DecOct(0)); - } else { - $v_typeflag = '0'; - clearstatcache(); - $v_size = sprintf("%011s", DecOct($v_info['size'])); - } - - $v_magic = 'ustar '; - - $v_version = ' '; - - if (function_exists('posix_getpwuid')) - { - $userinfo = posix_getpwuid($v_info[4]); - $groupinfo = posix_getgrgid($v_info[5]); - - $v_uname = $userinfo['name']; - $v_gname = $groupinfo['name']; - } - else - { - $v_uname = ''; - $v_gname = ''; - } - - $v_devmajor = ''; - - $v_devminor = ''; - - $v_prefix = ''; - - $v_binary_data_first = pack("a100a8a8a8a12a12", - $v_reduce_filename, $v_perms, $v_uid, - $v_gid, $v_size, $v_mtime); - $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", - $v_typeflag, $v_linkname, $v_magic, - $v_version, $v_uname, $v_gname, - $v_devmajor, $v_devminor, $v_prefix, ''); - - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum += ord(substr($v_binary_data_first,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156, $j=0; $i<512; $i++, $j++) - $v_checksum += ord(substr($v_binary_data_last,$j,1)); - - // ----- Write the first 148 bytes of the header in the archive - $this->_writeBlock($v_binary_data_first, 148); - - // ----- Write the calculated checksum - $v_checksum = sprintf("%06s ", DecOct($v_checksum)); - $v_binary_data = pack("a8", $v_checksum); - $this->_writeBlock($v_binary_data, 8); - - // ----- Write the last 356 bytes of the header in the archive - $this->_writeBlock($v_binary_data_last, 356); - - return true; - } - // }}} - - // {{{ _writeHeaderBlock() - function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, - $p_type='', $p_uid=0, $p_gid=0) - { - $p_filename = $this->_pathReduction($p_filename); - - if (strlen($p_filename) > 99) { - if (!$this->_writeLongHeader($p_filename)) - return false; - } - - if ($p_type == "5") { - $v_size = sprintf("%011s", DecOct(0)); - } else { - $v_size = sprintf("%011s", DecOct($p_size)); - } - - $v_uid = sprintf("%07s", DecOct($p_uid)); - $v_gid = sprintf("%07s", DecOct($p_gid)); - $v_perms = sprintf("%07s", DecOct($p_perms & 000777)); - - $v_mtime = sprintf("%11s", DecOct($p_mtime)); - - $v_linkname = ''; - - $v_magic = 'ustar '; - - $v_version = ' '; - - if (function_exists('posix_getpwuid')) - { - $userinfo = posix_getpwuid($p_uid); - $groupinfo = posix_getgrgid($p_gid); - - $v_uname = $userinfo['name']; - $v_gname = $groupinfo['name']; - } - else - { - $v_uname = ''; - $v_gname = ''; - } - - $v_devmajor = ''; - - $v_devminor = ''; - - $v_prefix = ''; - - $v_binary_data_first = pack("a100a8a8a8a12A12", - $p_filename, $v_perms, $v_uid, $v_gid, - $v_size, $v_mtime); - $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", - $p_type, $v_linkname, $v_magic, - $v_version, $v_uname, $v_gname, - $v_devmajor, $v_devminor, $v_prefix, ''); - - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum += ord(substr($v_binary_data_first,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156, $j=0; $i<512; $i++, $j++) - $v_checksum += ord(substr($v_binary_data_last,$j,1)); - - // ----- Write the first 148 bytes of the header in the archive - $this->_writeBlock($v_binary_data_first, 148); - - // ----- Write the calculated checksum - $v_checksum = sprintf("%06s ", DecOct($v_checksum)); - $v_binary_data = pack("a8", $v_checksum); - $this->_writeBlock($v_binary_data, 8); - - // ----- Write the last 356 bytes of the header in the archive - $this->_writeBlock($v_binary_data_last, 356); - - return true; - } - // }}} - - // {{{ _writeLongHeader() - function _writeLongHeader($p_filename) - { - $v_size = sprintf("%11s ", DecOct(strlen($p_filename))); - - $v_typeflag = 'L'; - - $v_linkname = ''; - - $v_magic = ''; - - $v_version = ''; - - $v_uname = ''; - - $v_gname = ''; - - $v_devmajor = ''; - - $v_devminor = ''; - - $v_prefix = ''; - - $v_binary_data_first = pack("a100a8a8a8a12a12", - '././@LongLink', 0, 0, 0, $v_size, 0); - $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", - $v_typeflag, $v_linkname, $v_magic, - $v_version, $v_uname, $v_gname, - $v_devmajor, $v_devminor, $v_prefix, ''); - - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum += ord(substr($v_binary_data_first,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156, $j=0; $i<512; $i++, $j++) - $v_checksum += ord(substr($v_binary_data_last,$j,1)); - - // ----- Write the first 148 bytes of the header in the archive - $this->_writeBlock($v_binary_data_first, 148); - - // ----- Write the calculated checksum - $v_checksum = sprintf("%06s ", DecOct($v_checksum)); - $v_binary_data = pack("a8", $v_checksum); - $this->_writeBlock($v_binary_data, 8); - - // ----- Write the last 356 bytes of the header in the archive - $this->_writeBlock($v_binary_data_last, 356); - - // ----- Write the filename as content of the block - $i=0; - while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') { - $v_binary_data = pack("a512", "$v_buffer"); - $this->_writeBlock($v_binary_data); - } - - return true; - } - // }}} - - // {{{ _readHeader() - function _readHeader($v_binary_data, &$v_header) - { - if (strlen($v_binary_data)==0) { - $v_header['filename'] = ''; - return true; - } - - if (strlen($v_binary_data) != 512) { - $v_header['filename'] = ''; - $this->_error('Invalid block size : '.strlen($v_binary_data)); - return false; - } - - if (!is_array($v_header)) { - $v_header = array(); - } - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum+=ord(substr($v_binary_data,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156; $i<512; $i++) - $v_checksum+=ord(substr($v_binary_data,$i,1)); - - $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" - ."a8checksum/a1typeflag/a100link/a6magic/a2version/" - ."a32uname/a32gname/a8devmajor/a8devminor", - $v_binary_data); - - // ----- Extract the checksum - $v_header['checksum'] = OctDec(trim($v_data['checksum'])); - if ($v_header['checksum'] != $v_checksum) { - $v_header['filename'] = ''; - - // ----- Look for last block (empty block) - if (($v_checksum == 256) && ($v_header['checksum'] == 0)) - return true; - - $this->_error('Invalid checksum for file "'.$v_data['filename'] - .'" : '.$v_checksum.' calculated, ' - .$v_header['checksum'].' expected'); - return false; - } - - // ----- Extract the properties - $v_header['filename'] = $v_data['filename']; - if ($this->_maliciousFilename($v_header['filename'])) { - $this->_error('Malicious .tar detected, file "' . $v_header['filename'] . - '" will not install in desired directory tree'); - return false; - } - $v_header['mode'] = OctDec(trim($v_data['mode'])); - $v_header['uid'] = OctDec(trim($v_data['uid'])); - $v_header['gid'] = OctDec(trim($v_data['gid'])); - $v_header['size'] = OctDec(trim($v_data['size'])); - $v_header['mtime'] = OctDec(trim($v_data['mtime'])); - if (($v_header['typeflag'] = $v_data['typeflag']) == "5") { - $v_header['size'] = 0; - } - $v_header['link'] = trim($v_data['link']); - /* ----- All these fields are removed form the header because - they do not carry interesting info - $v_header[magic] = trim($v_data[magic]); - $v_header[version] = trim($v_data[version]); - $v_header[uname] = trim($v_data[uname]); - $v_header[gname] = trim($v_data[gname]); - $v_header[devmajor] = trim($v_data[devmajor]); - $v_header[devminor] = trim($v_data[devminor]); - */ - - return true; - } - // }}} - - // {{{ _maliciousFilename() - /** - * Detect and report a malicious file name - * - * @param string $file - * @return bool - * @access private - */ - function _maliciousFilename($file) - { - if (strpos($file, '/../') !== false) { - return true; - } - if (strpos($file, '../') === 0) { - return true; - } - return false; - } - // }}} - - // {{{ _readLongHeader() - function _readLongHeader(&$v_header) - { - $v_filename = ''; - $n = floor($v_header['size']/512); - for ($i=0; $i<$n; $i++) { - $v_content = $this->_readBlock(); - $v_filename .= $v_content; - } - if (($v_header['size'] % 512) != 0) { - $v_content = $this->_readBlock(); - $v_filename .= trim($v_content); - } - - // ----- Read the next header - $v_binary_data = $this->_readBlock(); - - if (!$this->_readHeader($v_binary_data, $v_header)) - return false; - - $v_filename = trim($v_filename); - $v_header['filename'] = $v_filename; - if ($this->_maliciousFilename($v_filename)) { - $this->_error('Malicious .tar detected, file "' . $v_filename . - '" will not install in desired directory tree'); - return false; - } - - return true; - } - // }}} - - // {{{ _extractInString() - /** - * This method extract from the archive one file identified by $p_filename. - * The return value is a string with the file content, or NULL on error. - * @param string $p_filename The path of the file to extract in a string. - * @return a string with the file content or NULL. - * @access private - */ - function _extractInString($p_filename) - { - $v_result_str = ""; - - While (strlen($v_binary_data = $this->_readBlock()) != 0) - { - if (!$this->_readHeader($v_binary_data, $v_header)) - return NULL; - - if ($v_header['filename'] == '') - continue; - - // ----- Look for long filename - if ($v_header['typeflag'] == 'L') { - if (!$this->_readLongHeader($v_header)) - return NULL; - } - - if ($v_header['filename'] == $p_filename) { - if ($v_header['typeflag'] == "5") { - $this->_error('Unable to extract in string a directory ' - .'entry {'.$v_header['filename'].'}'); - return NULL; - } else { - $n = floor($v_header['size']/512); - for ($i=0; $i<$n; $i++) { - $v_result_str .= $this->_readBlock(); - } - if (($v_header['size'] % 512) != 0) { - $v_content = $this->_readBlock(); - $v_result_str .= substr($v_content, 0, - ($v_header['size'] % 512)); - } - return $v_result_str; - } - } else { - $this->_jumpBlock(ceil(($v_header['size']/512))); - } - } - - return NULL; - } - // }}} - - // {{{ _extractList() - function _extractList($p_path, &$p_list_detail, $p_mode, - $p_file_list, $p_remove_path) - { - $v_result=true; - $v_nb = 0; - $v_extract_all = true; - $v_listing = false; - - $p_path = $this->_translateWinPath($p_path, false); - if ($p_path == '' || (substr($p_path, 0, 1) != '/' - && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) { - $p_path = "./".$p_path; - } - $p_remove_path = $this->_translateWinPath($p_remove_path); - - // ----- Look for path to remove format (should end by /) - if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) - $p_remove_path .= '/'; - $p_remove_path_size = strlen($p_remove_path); - - switch ($p_mode) { - case "complete" : - $v_extract_all = TRUE; - $v_listing = FALSE; - break; - case "partial" : - $v_extract_all = FALSE; - $v_listing = FALSE; - break; - case "list" : - $v_extract_all = FALSE; - $v_listing = TRUE; - break; - default : - $this->_error('Invalid extract mode ('.$p_mode.')'); - return false; - } - - clearstatcache(); - - while (strlen($v_binary_data = $this->_readBlock()) != 0) - { - $v_extract_file = FALSE; - $v_extraction_stopped = 0; - - if (!$this->_readHeader($v_binary_data, $v_header)) - return false; - - if ($v_header['filename'] == '') { - continue; - } - - // ----- Look for long filename - if ($v_header['typeflag'] == 'L') { - if (!$this->_readLongHeader($v_header)) - return false; - } - - if ((!$v_extract_all) && (is_array($p_file_list))) { - // ----- By default no unzip if the file is not found - $v_extract_file = false; - - for ($i=0; $i strlen($p_file_list[$i])) - && (substr($v_header['filename'], 0, strlen($p_file_list[$i])) - == $p_file_list[$i])) { - $v_extract_file = TRUE; - break; - } - } - - // ----- It is a file, so compare the file names - elseif ($p_file_list[$i] == $v_header['filename']) { - $v_extract_file = TRUE; - break; - } - } - } else { - $v_extract_file = TRUE; - } - - // ----- Look if this file need to be extracted - if (($v_extract_file) && (!$v_listing)) - { - if (($p_remove_path != '') - && (substr($v_header['filename'], 0, $p_remove_path_size) - == $p_remove_path)) - $v_header['filename'] = substr($v_header['filename'], - $p_remove_path_size); - if (($p_path != './') && ($p_path != '/')) { - while (substr($p_path, -1) == '/') - $p_path = substr($p_path, 0, strlen($p_path)-1); - - if (substr($v_header['filename'], 0, 1) == '/') - $v_header['filename'] = $p_path.$v_header['filename']; - else - $v_header['filename'] = $p_path.'/'.$v_header['filename']; - } - if (file_exists($v_header['filename'])) { - if ( (@is_dir($v_header['filename'])) - && ($v_header['typeflag'] == '')) { - $this->_error('File '.$v_header['filename'] - .' already exists as a directory'); - return false; - } - if ( ($this->_isArchive($v_header['filename'])) - && ($v_header['typeflag'] == "5")) { - $this->_error('Directory '.$v_header['filename'] - .' already exists as a file'); - return false; - } - if (!is_writeable($v_header['filename'])) { - $this->_error('File '.$v_header['filename'] - .' already exists and is write protected'); - return false; - } - if (filemtime($v_header['filename']) > $v_header['mtime']) { - // To be completed : An error or silent no replace ? - } - } - - // ----- Check the directory availability and create it if necessary - elseif (($v_result - = $this->_dirCheck(($v_header['typeflag'] == "5" - ?$v_header['filename'] - :dirname($v_header['filename'])))) != 1) { - $this->_error('Unable to create path for '.$v_header['filename']); - return false; - } - - if ($v_extract_file) { - if ($v_header['typeflag'] == "5") { - if (!@file_exists($v_header['filename'])) { - if (!@mkdir($v_header['filename'], 0777)) { - $this->_error('Unable to create directory {' - .$v_header['filename'].'}'); - return false; - } - } - } elseif ($v_header['typeflag'] == "2") { - if (@file_exists($v_header['filename'])) { - @unlink($v_header['filename']); - } - if (!@symlink($v_header['link'], $v_header['filename'])) { - $this->_error('Unable to extract symbolic link {' - .$v_header['filename'].'}'); - return false; - } - } else { - if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) { - $this->_error('Error while opening {'.$v_header['filename'] - .'} in write binary mode'); - return false; - } else { - $n = floor($v_header['size']/512); - for ($i=0; $i<$n; $i++) { - $v_content = $this->_readBlock(); - fwrite($v_dest_file, $v_content, 512); - } - if (($v_header['size'] % 512) != 0) { - $v_content = $this->_readBlock(); - fwrite($v_dest_file, $v_content, ($v_header['size'] % 512)); - } - - @fclose($v_dest_file); - - // ----- Change the file mode, mtime - @touch($v_header['filename'], $v_header['mtime']); - if ($v_header['mode'] & 0111) { - // make file executable, obey umask - $mode = fileperms($v_header['filename']) | (~umask() & 0111); - @chmod($v_header['filename'], $mode); - } - } - - // ----- Check the file size - clearstatcache(); - if (filesize($v_header['filename']) != $v_header['size']) { - $this->_error('Extracted file '.$v_header['filename'] - .' does not have the correct file size \'' - .filesize($v_header['filename']) - .'\' ('.$v_header['size'] - .' expected). Archive may be corrupted.'); - return false; - } - } - } else { - $this->_jumpBlock(ceil(($v_header['size']/512))); - } - } else { - $this->_jumpBlock(ceil(($v_header['size']/512))); - } - - /* TBC : Seems to be unused ... - if ($this->_compress) - $v_end_of_file = @gzeof($this->_file); - else - $v_end_of_file = @feof($this->_file); - */ - - if ($v_listing || $v_extract_file || $v_extraction_stopped) { - // ----- Log extracted files - if (($v_file_dir = dirname($v_header['filename'])) - == $v_header['filename']) - $v_file_dir = ''; - if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) - $v_file_dir = '/'; - - $p_list_detail[$v_nb++] = $v_header; - if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) { - return true; - } - } - } - - return true; - } - // }}} - - // {{{ _openAppend() - function _openAppend() - { - if (filesize($this->_tarname) == 0) - return $this->_openWrite(); - - if ($this->_compress) { - $this->_close(); - - if (!@rename($this->_tarname, $this->_tarname.".tmp")) { - $this->_error('Error while renaming \''.$this->_tarname - .'\' to temporary file \''.$this->_tarname - .'.tmp\''); - return false; - } - - if ($this->_compress_type == 'gz') - $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb"); - elseif ($this->_compress_type == 'bz2') - $v_temp_tar = @bzopen($this->_tarname.".tmp", "r"); - - if ($v_temp_tar == 0) { - $this->_error('Unable to open file \''.$this->_tarname - .'.tmp\' in binary read mode'); - @rename($this->_tarname.".tmp", $this->_tarname); - return false; - } - - if (!$this->_openWrite()) { - @rename($this->_tarname.".tmp", $this->_tarname); - return false; - } - - if ($this->_compress_type == 'gz') { - while (!@gzeof($v_temp_tar)) { - $v_buffer = @gzread($v_temp_tar, 512); - if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { - // do not copy end blocks, we will re-make them - // after appending - continue; - } - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - } - - @gzclose($v_temp_tar); - } - elseif ($this->_compress_type == 'bz2') { - while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) { - if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { - continue; - } - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - } - - @bzclose($v_temp_tar); - } - - if (!@unlink($this->_tarname.".tmp")) { - $this->_error('Error while deleting temporary file \'' - .$this->_tarname.'.tmp\''); - } - - } else { - // ----- For not compressed tar, just add files before the last - // one or two 512 bytes block - if (!$this->_openReadWrite()) - return false; - - clearstatcache(); - $v_size = filesize($this->_tarname); - - // We might have zero, one or two end blocks. - // The standard is two, but we should try to handle - // other cases. - fseek($this->_file, $v_size - 1024); - if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { - fseek($this->_file, $v_size - 1024); - } - elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { - fseek($this->_file, $v_size - 512); - } - } - - return true; - } - // }}} - - // {{{ _append() - function _append($p_filelist, $p_add_dir='', $p_remove_dir='') - { - if (!$this->_openAppend()) - return false; - - if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) - $this->_writeFooter(); - - $this->_close(); - - return true; - } - // }}} - - // {{{ _dirCheck() - - /** - * Check if a directory exists and create it (including parent - * dirs) if not. - * - * @param string $p_dir directory to check - * - * @return bool TRUE if the directory exists or was created - */ - function _dirCheck($p_dir) - { - clearstatcache(); - if ((@is_dir($p_dir)) || ($p_dir == '')) - return true; - - $p_parent_dir = dirname($p_dir); - - if (($p_parent_dir != $p_dir) && - ($p_parent_dir != '') && - (!$this->_dirCheck($p_parent_dir))) - return false; - - if (!@mkdir($p_dir, 0777)) { - $this->_error("Unable to create directory '$p_dir'"); - return false; - } - - return true; - } - - // }}} - - // {{{ _pathReduction() - - /** - * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", - * rand emove double slashes. - * - * @param string $p_dir path to reduce - * - * @return string reduced path - * - * @access private - * - */ - function _pathReduction($p_dir) - { - $v_result = ''; - - // ----- Look for not empty path - if ($p_dir != '') { - // ----- Explode path by directory names - $v_list = explode('/', $p_dir); - - // ----- Study directories from last to first - for ($i=sizeof($v_list)-1; $i>=0; $i--) { - // ----- Look for current path - if ($v_list[$i] == ".") { - // ----- Ignore this directory - // Should be the first $i=0, but no check is done - } - else if ($v_list[$i] == "..") { - // ----- Ignore it and ignore the $i-1 - $i--; - } - else if ( ($v_list[$i] == '') - && ($i!=(sizeof($v_list)-1)) - && ($i!=0)) { - // ----- Ignore only the double '//' in path, - // but not the first and last / - } else { - $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/' - .$v_result:''); - } - } - } - $v_result = strtr($v_result, '\\', '/'); - return $v_result; - } - - // }}} - - // {{{ _translateWinPath() - function _translateWinPath($p_path, $p_remove_disk_letter=true) - { - if (defined('OS_WINDOWS') && OS_WINDOWS) { - // ----- Look for potential disk letter - if ( ($p_remove_disk_letter) - && (($v_position = strpos($p_path, ':')) != false)) { - $p_path = substr($p_path, $v_position+1); - } - // ----- Change potential windows directory separator - if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { - $p_path = strtr($p_path, '\\', '/'); - } - } - return $p_path; - } - // }}} - -} -?> - - * @license http://www.php.net/license/3_0.txt PHP 3.0 - * @version CVS: $Id: Getopt.php 267328 2008-10-14 18:53:25Z andrei $ - * @link http://pear.php.net/package/Console_Getopt - */ - -require_once 'phar://go-pear.phar/' . 'PEAR.php'; - -/** - * Command-line options parsing class. - * - * @category Console - * @package Console_Getopt - * @author Andrei Zmievski - * @license http://www.php.net/license/3_0.txt PHP 3.0 - * @link http://pear.php.net/package/Console_Getopt - */ -class Console_Getopt -{ - - /** - * Parses the command-line options. - * - * The first parameter to this function should be the list of command-line - * arguments without the leading reference to the running program. - * - * The second parameter is a string of allowed short options. Each of the - * option letters can be followed by a colon ':' to specify that the option - * requires an argument, or a double colon '::' to specify that the option - * takes an optional argument. - * - * The third argument is an optional array of allowed long options. The - * leading '--' should not be included in the option name. Options that - * require an argument should be followed by '=', and options that take an - * option argument should be followed by '=='. - * - * The return value is an array of two elements: the list of parsed - * options and the list of non-option command-line arguments. Each entry in - * the list of parsed options is a pair of elements - the first one - * specifies the option, and the second one specifies the option argument, - * if there was one. - * - * Long and short options can be mixed. - * - * Most of the semantics of this function are based on GNU getopt_long(). - * - * @param array $args an array of command-line arguments - * @param string $short_options specifies the list of allowed short options - * @param array $long_options specifies the list of allowed long options - * - * @return array two-element array containing the list of parsed options and - * the non-option arguments - * @access public - */ - function getopt2($args, $short_options, $long_options = null) - { - return Console_Getopt::doGetopt(2, $args, $short_options, $long_options); - } - - /** - * This function expects $args to start with the script name (POSIX-style). - * Preserved for backwards compatibility. - * - * @param array $args an array of command-line arguments - * @param string $short_options specifies the list of allowed short options - * @param array $long_options specifies the list of allowed long options - * - * @see getopt2() - * @return array two-element array containing the list of parsed options and - * the non-option arguments - */ - function getopt($args, $short_options, $long_options = null) - { - return Console_Getopt::doGetopt(1, $args, $short_options, $long_options); - } - - /** - * The actual implementation of the argument parsing code. - * - * @param int $version Version to use - * @param array $args an array of command-line arguments - * @param string $short_options specifies the list of allowed short options - * @param array $long_options specifies the list of allowed long options - * - * @return array - */ - function doGetopt($version, $args, $short_options, $long_options = null) - { - // in case you pass directly readPHPArgv() as the first arg - if (PEAR::isError($args)) { - return $args; - } - if (empty($args)) { - return array(array(), array()); - } - $opts = array(); - $non_opts = array(); - - settype($args, 'array'); - - if ($long_options) { - sort($long_options); - } - - /* - * Preserve backwards compatibility with callers that relied on - * erroneous POSIX fix. - */ - if ($version < 2) { - if (isset($args[0]{0}) && $args[0]{0} != '-') { - array_shift($args); - } - } - - reset($args); - while (list($i, $arg) = each($args)) { - - /* The special element '--' means explicit end of - options. Treat the rest of the arguments as non-options - and end the loop. */ - if ($arg == '--') { - $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); - break; - } - - if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' - && !$long_options)) { - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } elseif (strlen($arg) > 1 && $arg{1} == '-') { - $error = Console_Getopt::_parseLongOption(substr($arg, 2), - $long_options, $opts, - $args); - if (PEAR::isError($error)) { - return $error; - } - } elseif ($arg == '-') { - // - is stdin - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } else { - $error = Console_Getopt::_parseShortOption(substr($arg, 1), - $short_options, $opts, - $args); - if (PEAR::isError($error)) { - return $error; - } - } - } - - return array($opts, $non_opts); - } - - /** - * Parse short option - * - * @param string $arg Argument - * @param string[] $short_options Available short options - * @param string[][] &$opts - * @param string[] &$args - * - * @access private - * @return void - */ - function _parseShortOption($arg, $short_options, &$opts, &$args) - { - for ($i = 0; $i < strlen($arg); $i++) { - $opt = $arg{$i}; - $opt_arg = null; - - /* Try to find the short option in the specifier string. */ - if (($spec = strstr($short_options, $opt)) === false - || $arg{$i} == ':') { - $msg = "Console_Getopt: unrecognized option -- $opt"; - return PEAR::raiseError($msg); - } - - if (strlen($spec) > 1 && $spec{1} == ':') { - if (strlen($spec) > 2 && $spec{2} == ':') { - if ($i + 1 < strlen($arg)) { - /* Option takes an optional argument. Use the remainder of - the arg string if there is anything left. */ - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - } else { - /* Option requires an argument. Use the remainder of the arg - string if there is anything left. */ - if ($i + 1 < strlen($arg)) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } else if (list(, $opt_arg) = each($args)) { - /* Else use the next argument. */; - if (Console_Getopt::_isShortOpt($opt_arg) - || Console_Getopt::_isLongOpt($opt_arg)) { - $msg = "option requires an argument --$opt"; - return PEAR::raiseError("Console_Getopt:" . $msg); - } - } else { - $msg = "option requires an argument --$opt"; - return PEAR::raiseError("Console_Getopt:" . $msg); - } - } - } - - $opts[] = array($opt, $opt_arg); - } - } - - /** - * Checks if an argument is a short option - * - * @param string $arg Argument to check - * - * @access private - * @return bool - */ - function _isShortOpt($arg) - { - return strlen($arg) == 2 && $arg[0] == '-' - && preg_match('/[a-zA-Z]/', $arg[1]); - } - - /** - * Checks if an argument is a long option - * - * @param string $arg Argument to check - * - * @access private - * @return bool - */ - function _isLongOpt($arg) - { - return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && - preg_match('/[a-zA-Z]+$/', substr($arg, 2)); - } - - /** - * Parse long option - * - * @param string $arg Argument - * @param string[] $long_options Available long options - * @param string[][] &$opts - * @param string[] &$args - * - * @access private - * @return void|PEAR_Error - */ - function _parseLongOption($arg, $long_options, &$opts, &$args) - { - @list($opt, $opt_arg) = explode('=', $arg, 2); - - $opt_len = strlen($opt); - - for ($i = 0; $i < count($long_options); $i++) { - $long_opt = $long_options[$i]; - $opt_start = substr($long_opt, 0, $opt_len); - - $long_opt_name = str_replace('=', '', $long_opt); - - /* Option doesn't match. Go on to the next one. */ - if ($long_opt_name != $opt) { - continue; - } - - $opt_rest = substr($long_opt, $opt_len); - - /* Check that the options uniquely matches one of the allowed - options. */ - if ($i + 1 < count($long_options)) { - $next_option_rest = substr($long_options[$i + 1], $opt_len); - } else { - $next_option_rest = ''; - } - - if ($opt_rest != '' && $opt{0} != '=' && - $i + 1 < count($long_options) && - $opt == substr($long_options[$i+1], 0, $opt_len) && - $next_option_rest != '' && - $next_option_rest{0} != '=') { - - $msg = "Console_Getopt: option --$opt is ambiguous"; - return PEAR::raiseError($msg); - } - - if (substr($long_opt, -1) == '=') { - if (substr($long_opt, -2) != '==') { - /* Long option requires an argument. - Take the next argument if one wasn't specified. */; - if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { - $msg = "Console_Getopt: option requires an argument --$opt"; - return PEAR::raiseError($msg); - } - - if (Console_Getopt::_isShortOpt($opt_arg) - || Console_Getopt::_isLongOpt($opt_arg)) { - $msg = "Console_Getopt: option requires an argument --$opt"; - return PEAR::raiseError($msg); - } - } - } else if ($opt_arg) { - $msg = "Console_Getopt: option --$opt doesn't allow an argument"; - return PEAR::raiseError($msg); - } - - $opts[] = array('--' . $opt, $opt_arg); - return; - } - - return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); - } - - /** - * Safely read the $argv PHP array across different PHP configurations. - * Will take care on register_globals and register_argc_argv ini directives - * - * @access public - * @return mixed the $argv PHP array or PEAR error if not registered - */ - function readPHPArgv() - { - global $argv; - if (!is_array($argv)) { - if (!@is_array($_SERVER['argv'])) { - if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { - $msg = "Could not read cmd args (register_argc_argv=Off?)"; - return PEAR::raiseError("Console_Getopt: " . $msg); - } - return $GLOBALS['HTTP_SERVER_VARS']['argv']; - } - return $_SERVER['argv']; - } - return $argv; - } - -} - -?> -run(); -?> - * @author Gregory Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Guess.php 278521 2009-04-09 22:24:12Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since PEAR 0.1 - */ - -// {{{ uname examples - -// php_uname() without args returns the same as 'uname -a', or a PHP-custom -// string for Windows. -// PHP versions prior to 4.3 return the uname of the host where PHP was built, -// as of 4.3 it returns the uname of the host running the PHP code. -// -// PC RedHat Linux 7.1: -// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown -// -// PC Debian Potato: -// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown -// -// PC FreeBSD 3.3: -// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386 -// -// PC FreeBSD 4.3: -// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386 -// -// PC FreeBSD 4.5: -// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386 -// -// PC FreeBSD 4.5 w/uname from GNU shellutils: -// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown -// -// HP 9000/712 HP-UX 10: -// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license -// -// HP 9000/712 HP-UX 10 w/uname from GNU shellutils: -// HP-UX host B.10.10 A 9000/712 unknown -// -// IBM RS6000/550 AIX 4.3: -// AIX host 3 4 000003531C00 -// -// AIX 4.3 w/uname from GNU shellutils: -// AIX host 3 4 000003531C00 unknown -// -// SGI Onyx IRIX 6.5 w/uname from GNU shellutils: -// IRIX64 host 6.5 01091820 IP19 mips -// -// SGI Onyx IRIX 6.5: -// IRIX64 host 6.5 01091820 IP19 -// -// SparcStation 20 Solaris 8 w/uname from GNU shellutils: -// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc -// -// SparcStation 20 Solaris 8: -// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20 -// -// Mac OS X (Darwin) -// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh -// -// Mac OS X early versions -// - -// }}} - -/* TODO: - * - define endianness, to allow matchSignature("bigend") etc. - */ - -/** - * Retrieves information about the current operating system - * - * This class uses php_uname() to grok information about the current OS - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Gregory Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class OS_Guess -{ - var $sysname; - var $nodename; - var $cpu; - var $release; - var $extra; - - function OS_Guess($uname = null) - { - list($this->sysname, - $this->release, - $this->cpu, - $this->extra, - $this->nodename) = $this->parseSignature($uname); - } - - function parseSignature($uname = null) - { - static $sysmap = array( - 'HP-UX' => 'hpux', - 'IRIX64' => 'irix', - ); - static $cpumap = array( - 'i586' => 'i386', - 'i686' => 'i386', - 'ppc' => 'powerpc', - ); - if ($uname === null) { - $uname = php_uname(); - } - $parts = preg_split('/\s+/', trim($uname)); - $n = count($parts); - - $release = $machine = $cpu = ''; - $sysname = $parts[0]; - $nodename = $parts[1]; - $cpu = $parts[$n-1]; - $extra = ''; - if ($cpu == 'unknown') { - $cpu = $parts[$n - 2]; - } - - switch ($sysname) { - case 'AIX' : - $release = "$parts[3].$parts[2]"; - break; - case 'Windows' : - switch ($parts[1]) { - case '95/98': - $release = '9x'; - break; - default: - $release = $parts[1]; - break; - } - $cpu = 'i386'; - break; - case 'Linux' : - $extra = $this->_detectGlibcVersion(); - // use only the first two digits from the kernel version - $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); - break; - case 'Mac' : - $sysname = 'darwin'; - $nodename = $parts[2]; - $release = $parts[3]; - if ($cpu == 'Macintosh') { - if ($parts[$n - 2] == 'Power') { - $cpu = 'powerpc'; - } - } - break; - case 'Darwin' : - if ($cpu == 'Macintosh') { - if ($parts[$n - 2] == 'Power') { - $cpu = 'powerpc'; - } - } - $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); - break; - default: - $release = preg_replace('/-.*/', '', $parts[2]); - break; - } - - if (isset($sysmap[$sysname])) { - $sysname = $sysmap[$sysname]; - } else { - $sysname = strtolower($sysname); - } - if (isset($cpumap[$cpu])) { - $cpu = $cpumap[$cpu]; - } - return array($sysname, $release, $cpu, $extra, $nodename); - } - - function _detectGlibcVersion() - { - static $glibc = false; - if ($glibc !== false) { - return $glibc; // no need to run this multiple times - } - $major = $minor = 0; - include_once 'phar://go-pear.phar/' . "System.php"; - // Use glibc's header file to - // get major and minor version number: - if (@file_exists('/usr/include/features.h') && - @is_readable('/usr/include/features.h')) { - if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) { - $features_file = fopen('/usr/include/features.h', 'rb'); - while (!feof($features_file)) { - $line = fgets($features_file, 8192); - if (!$line || (strpos($line, '#define') === false)) { - continue; - } - if (strpos($line, '__GLIBC__')) { - // major version number #define __GLIBC__ version - $line = preg_split('/\s+/', $line); - $glibc_major = trim($line[2]); - if (isset($glibc_minor)) { - break; - } - continue; - } - - if (strpos($line, '__GLIBC_MINOR__')) { - // got the minor version number - // #define __GLIBC_MINOR__ version - $line = preg_split('/\s+/', $line); - $glibc_minor = trim($line[2]); - if (isset($glibc_major)) { - break; - } - continue; - } - } - fclose($features_file); - if (!isset($glibc_major) || !isset($glibc_minor)) { - return $glibc = ''; - } - return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ; - } // no cpp - - $tmpfile = System::mktemp("glibctest"); - $fp = fopen($tmpfile, "w"); - fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n"); - fclose($fp); - $cpp = popen("/usr/bin/cpp $tmpfile", "r"); - while ($line = fgets($cpp, 1024)) { - if ($line{0} == '#' || trim($line) == '') { - continue; - } - - if (list($major, $minor) = explode(' ', trim($line))) { - break; - } - } - pclose($cpp); - unlink($tmpfile); - } // features.h - - if (!($major && $minor) && @is_link('/lib/libc.so.6')) { - // Let's try reading the libc.so.6 symlink - if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) { - list($major, $minor) = explode('.', $matches[1]); - } - } - - if (!($major && $minor)) { - return $glibc = ''; - } - - return $glibc = "glibc{$major}.{$minor}"; - } - - function getSignature() - { - if (empty($this->extra)) { - return "{$this->sysname}-{$this->release}-{$this->cpu}"; - } - return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}"; - } - - function getSysname() - { - return $this->sysname; - } - - function getNodename() - { - return $this->nodename; - } - - function getCpu() - { - return $this->cpu; - } - - function getRelease() - { - return $this->release; - } - - function getExtra() - { - return $this->extra; - } - - function matchSignature($match) - { - $fragments = is_array($match) ? $match : explode('-', $match); - $n = count($fragments); - $matches = 0; - if ($n > 0) { - $matches += $this->_matchFragment($fragments[0], $this->sysname); - } - if ($n > 1) { - $matches += $this->_matchFragment($fragments[1], $this->release); - } - if ($n > 2) { - $matches += $this->_matchFragment($fragments[2], $this->cpu); - } - if ($n > 3) { - $matches += $this->_matchFragment($fragments[3], $this->extra); - } - return ($matches == $n); - } - - function _matchFragment($fragment, $value) - { - if (strcspn($fragment, '*?') < strlen($fragment)) { - $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/'; - return preg_match($reg, $value); - } - return ($fragment == '*' || !strcasecmp($fragment, $value)); - } - -} -/* - * Local Variables: - * indent-tabs-mode: nil - * c-basic-offset: 4 - * End: - */ - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PEAR.php 286670 2009-08-02 14:16:06Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/**#@+ - * ERROR constants - */ -define('PEAR_ERROR_RETURN', 1); -define('PEAR_ERROR_PRINT', 2); -define('PEAR_ERROR_TRIGGER', 4); -define('PEAR_ERROR_DIE', 8); -define('PEAR_ERROR_CALLBACK', 16); -/** - * WARNING: obsolete - * @deprecated - */ -define('PEAR_ERROR_EXCEPTION', 32); -/**#@-*/ -define('PEAR_ZE2', (function_exists('version_compare') && - version_compare(zend_version(), "2-dev", "ge"))); - -if (substr(PHP_OS, 0, 3) == 'WIN') { - define('OS_WINDOWS', true); - define('OS_UNIX', false); - define('PEAR_OS', 'Windows'); -} else { - define('OS_WINDOWS', false); - define('OS_UNIX', true); - define('PEAR_OS', 'Unix'); // blatant assumption -} - -$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; -$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; -$GLOBALS['_PEAR_destructor_object_list'] = array(); -$GLOBALS['_PEAR_shutdown_funcs'] = array(); -$GLOBALS['_PEAR_error_handler_stack'] = array(); - -@ini_set('track_errors', true); - -/** - * Base class for other PEAR classes. Provides rudimentary - * emulation of destructors. - * - * If you want a destructor in your class, inherit PEAR and make a - * destructor method called _yourclassname (same name as the - * constructor, but with a "_" prefix). Also, in your constructor you - * have to call the PEAR constructor: $this->PEAR();. - * The destructor method will be called without parameters. Note that - * at in some SAPI implementations (such as Apache), any output during - * the request shutdown (in which destructors are called) seems to be - * discarded. If you need to get any debug information from your - * destructor, use error_log(), syslog() or something similar. - * - * IMPORTANT! To use the emulated destructors you need to create the - * objects by reference: $obj =& new PEAR_child; - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @see PEAR_Error - * @since Class available since PHP 4.0.2 - * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear - */ -class PEAR -{ - // {{{ properties - - /** - * Whether to enable internal debug messages. - * - * @var bool - * @access private - */ - var $_debug = false; - - /** - * Default error mode for this object. - * - * @var int - * @access private - */ - var $_default_error_mode = null; - - /** - * Default error options used for this object when error mode - * is PEAR_ERROR_TRIGGER. - * - * @var int - * @access private - */ - var $_default_error_options = null; - - /** - * Default error handler (callback) for this object, if error mode is - * PEAR_ERROR_CALLBACK. - * - * @var string - * @access private - */ - var $_default_error_handler = ''; - - /** - * Which class to use for error objects. - * - * @var string - * @access private - */ - var $_error_class = 'PEAR_Error'; - - /** - * An array of expected errors. - * - * @var array - * @access private - */ - var $_expected_errors = array(); - - // }}} - - // {{{ constructor - - /** - * Constructor. Registers this object in - * $_PEAR_destructor_object_list for destructor emulation if a - * destructor object exists. - * - * @param string $error_class (optional) which class to use for - * error objects, defaults to PEAR_Error. - * @access public - * @return void - */ - function PEAR($error_class = null) - { - $classname = strtolower(get_class($this)); - if ($this->_debug) { - print "PEAR constructor called, class=$classname\n"; - } - if ($error_class !== null) { - $this->_error_class = $error_class; - } - while ($classname && strcasecmp($classname, "pear")) { - $destructor = "_$classname"; - if (method_exists($this, $destructor)) { - global $_PEAR_destructor_object_list; - $_PEAR_destructor_object_list[] = &$this; - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - break; - } else { - $classname = get_parent_class($classname); - } - } - } - - // }}} - // {{{ destructor - - /** - * Destructor (the emulated type of...). Does nothing right now, - * but is included for forward compatibility, so subclass - * destructors should always call it. - * - * See the note in the class desciption about output from - * destructors. - * - * @access public - * @return void - */ - function _PEAR() { - if ($this->_debug) { - printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); - } - } - - // }}} - // {{{ getStaticProperty() - - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - function &getStaticProperty($class, $var) - { - static $properties; - if (!isset($properties[$class])) { - $properties[$class] = array(); - } - - if (!array_key_exists($var, $properties[$class])) { - $properties[$class][$var] = null; - } - - return $properties[$class][$var]; - } - - // }}} - // {{{ registerShutdownFunc() - - /** - * Use this function to register a shutdown method for static - * classes. - * - * @access public - * @param mixed $func The function name (or array of class/method) to call - * @param mixed $args The arguments to pass to the function - * @return void - */ - function registerShutdownFunc($func, $args = array()) - { - // if we are called statically, there is a potential - // that no shutdown func is registered. Bug #6445 - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); - } - - // }}} - // {{{ isError() - - /** - * Tell whether a value is a PEAR error. - * - * @param mixed $data the value to test - * @param int $code if $data is an error object, return true - * only if $code is a string and - * $obj->getMessage() == $code or - * $code is an integer and $obj->getCode() == $code - * @access public - * @return bool true if parameter is an error - */ - function isError($data, $code = null) - { - if (!is_a($data, 'PEAR_Error')) { - return false; - } - - if (is_null($code)) { - return true; - } elseif (is_string($code)) { - return $data->getMessage() == $code; - } - - return $data->getCode() == $code; - } - - // }}} - // {{{ setErrorHandling() - - /** - * Sets how errors generated by this object should be handled. - * Can be invoked both in objects and statically. If called - * statically, setErrorHandling sets the default behaviour for all - * PEAR objects. If called in an object, setErrorHandling sets - * the default behaviour for that object. - * - * @param int $mode - * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. - * - * @param mixed $options - * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one - * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * - * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected - * to be the callback function or method. A callback - * function is a string with the name of the function, a - * callback method is an array of two elements: the element - * at index 0 is the object, and the element at index 1 is - * the name of the method to call in the object. - * - * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is - * a printf format string used when printing the error - * message. - * - * @access public - * @return void - * @see PEAR_ERROR_RETURN - * @see PEAR_ERROR_PRINT - * @see PEAR_ERROR_TRIGGER - * @see PEAR_ERROR_DIE - * @see PEAR_ERROR_CALLBACK - * @see PEAR_ERROR_EXCEPTION - * - * @since PHP 4.0.5 - */ - - function setErrorHandling($mode = null, $options = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $setmode = &$this->_default_error_mode; - $setoptions = &$this->_default_error_options; - } else { - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - } - - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - } - - // }}} - // {{{ expectError() - - /** - * This method is used to tell which errors you expect to get. - * Expected errors are always returned with error mode - * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, - * and this method pushes a new element onto it. The list of - * expected errors are in effect until they are popped off the - * stack with the popExpect() method. - * - * Note that this method can not be called statically - * - * @param mixed $code a single error code or an array of error codes to expect - * - * @return int the new depth of the "expected errors" stack - * @access public - */ - function expectError($code = '*') - { - if (is_array($code)) { - array_push($this->_expected_errors, $code); - } else { - array_push($this->_expected_errors, array($code)); - } - return sizeof($this->_expected_errors); - } - - // }}} - // {{{ popExpect() - - /** - * This method pops one element off the expected error codes - * stack. - * - * @return array the list of error codes that were popped - */ - function popExpect() - { - return array_pop($this->_expected_errors); - } - - // }}} - // {{{ _checkDelExpect() - - /** - * This method checks unsets an error code if available - * - * @param mixed error code - * @return bool true if the error code was unset, false otherwise - * @access private - * @since PHP 4.3.0 - */ - function _checkDelExpect($error_code) - { - $deleted = false; - - foreach ($this->_expected_errors AS $key => $error_array) { - if (in_array($error_code, $error_array)) { - unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); - $deleted = true; - } - - // clean up empty arrays - if (0 == count($this->_expected_errors[$key])) { - unset($this->_expected_errors[$key]); - } - } - return $deleted; - } - - // }}} - // {{{ delExpect() - - /** - * This method deletes all occurences of the specified element from - * the expected error codes stack. - * - * @param mixed $error_code error code that should be deleted - * @return mixed list of error codes that were deleted or error - * @access public - * @since PHP 4.3.0 - */ - function delExpect($error_code) - { - $deleted = false; - if ((is_array($error_code) && (0 != count($error_code)))) { - // $error_code is a non-empty array here; - // we walk through it trying to unset all - // values - foreach($error_code as $key => $error) { - if ($this->_checkDelExpect($error)) { - $deleted = true; - } else { - $deleted = false; - } - } - return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } elseif (!empty($error_code)) { - // $error_code comes alone, trying to unset it - if ($this->_checkDelExpect($error_code)) { - return true; - } else { - return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } - } - - // $error_code is empty - return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME - } - - // }}} - // {{{ raiseError() - - /** - * This method is a wrapper that returns an instance of the - * configured error class with this object's default error - * handling applied. If the $mode and $options parameters are not - * specified, the object's defaults are used. - * - * @param mixed $message a text error message or a PEAR error object - * - * @param int $code a numeric error code (it is up to your class - * to define these if you want to use codes) - * - * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. - * - * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter - * specifies the PHP-internal error level (one of - * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * If $mode is PEAR_ERROR_CALLBACK, this - * parameter specifies the callback function or - * method. In other error modes this parameter - * is ignored. - * - * @param string $userinfo If you need to pass along for example debug - * information, this parameter is meant for that. - * - * @param string $error_class The returned error object will be - * instantiated from this class, if specified. - * - * @param bool $skipmsg If true, raiseError will only pass error codes, - * the error message parameter will be dropped. - * - * @access public - * @return object a PEAR error object - * @see PEAR::setErrorHandling - * @since PHP 4.0.5 - */ - function &raiseError($message = null, - $code = null, - $mode = null, - $options = null, - $userinfo = null, - $error_class = null, - $skipmsg = false) - { - // The error is yet a PEAR error object - if (is_object($message)) { - $code = $message->getCode(); - $userinfo = $message->getUserInfo(); - $error_class = $message->getType(); - $message->error_message_prefix = ''; - $message = $message->getMessage(); - } - - if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { - if ($exp[0] == "*" || - (is_int(reset($exp)) && in_array($code, $exp)) || - (is_string(reset($exp)) && in_array($message, $exp))) { - $mode = PEAR_ERROR_RETURN; - } - } - - // No mode given, try global ones - if ($mode === null) { - // Class error handler - if (isset($this) && isset($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - $options = $this->_default_error_options; - // Global error handler - } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { - $mode = $GLOBALS['_PEAR_default_error_mode']; - $options = $GLOBALS['_PEAR_default_error_options']; - } - } - - if ($error_class !== null) { - $ec = $error_class; - } elseif (isset($this) && isset($this->_error_class)) { - $ec = $this->_error_class; - } else { - $ec = 'PEAR_Error'; - } - - if (intval(PHP_VERSION) < 5) { - // little non-eval hack to fix bug #12147 - include 'phar://go-pear.phar/' . 'PEAR/FixPHP5PEARWarnings.php'; - return $a; - } - - if ($skipmsg) { - $a = new $ec($code, $mode, $options, $userinfo); - } else { - $a = new $ec($message, $code, $mode, $options, $userinfo); - } - - return $a; - } - - // }}} - // {{{ throwError() - - /** - * Simpler form of raiseError with fewer options. In most cases - * message, code and userinfo are enough. - * - * @param string $message - * - */ - function &throwError($message = null, - $code = null, - $userinfo = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $a = &$this->raiseError($message, $code, null, null, $userinfo); - return $a; - } - - $a = &PEAR::raiseError($message, $code, null, null, $userinfo); - return $a; - } - - // }}} - function staticPushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - $stack[] = array($def_mode, $def_options); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $def_mode = $mode; - $def_options = $options; - break; - - case PEAR_ERROR_CALLBACK: - $def_mode = $mode; - // class/object method callback - if (is_callable($options)) { - $def_options = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - $stack[] = array($mode, $options); - return true; - } - - function staticPopErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - return true; - } - - // {{{ pushErrorHandling() - - /** - * Push a new error handler on top of the error handler options stack. With this - * you can easily override the actual error handler for some code and restore - * it later with popErrorHandling. - * - * @param mixed $mode (same as setErrorHandling) - * @param mixed $options (same as setErrorHandling) - * - * @return bool Always true - * - * @see PEAR::setErrorHandling - */ - function pushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - if (isset($this) && is_a($this, 'PEAR')) { - $def_mode = &$this->_default_error_mode; - $def_options = &$this->_default_error_options; - } else { - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - } - $stack[] = array($def_mode, $def_options); - - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); - } - $stack[] = array($mode, $options); - return true; - } - - // }}} - // {{{ popErrorHandling() - - /** - * Pop the last error handler used - * - * @return bool Always true - * - * @see PEAR::pushErrorHandling - */ - function popErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); - } - return true; - } - - // }}} - // {{{ loadExtension() - - /** - * OS independant PHP extension load. Remember to take care - * on the correct extension name for case sensitive OSes. - * - * @param string $ext The extension name - * @return bool Success or not on the dl() call - */ - function loadExtension($ext) - { - if (!extension_loaded($ext)) { - // if either returns true dl() will produce a FATAL error, stop that - if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { - return false; - } - - if (OS_WINDOWS) { - $suffix = '.dll'; - } elseif (PHP_OS == 'HP-UX') { - $suffix = '.sl'; - } elseif (PHP_OS == 'AIX') { - $suffix = '.a'; - } elseif (PHP_OS == 'OSX') { - $suffix = '.bundle'; - } else { - $suffix = '.so'; - } - - return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); - } - - return true; - } - - // }}} -} - -if (PEAR_ZE2) { - include_once 'phar://go-pear.phar/' . 'PEAR5.php'; -} - -// {{{ _PEAR_call_destructors() - -function _PEAR_call_destructors() -{ - global $_PEAR_destructor_object_list; - if (is_array($_PEAR_destructor_object_list) && - sizeof($_PEAR_destructor_object_list)) - { - reset($_PEAR_destructor_object_list); - if (PEAR_ZE2) { - $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); - } else { - $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); - } - - if ($destructLifoExists) { - $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); - } - - while (list($k, $objref) = each($_PEAR_destructor_object_list)) { - $classname = get_class($objref); - while ($classname) { - $destructor = "_$classname"; - if (method_exists($objref, $destructor)) { - $objref->$destructor(); - break; - } else { - $classname = get_parent_class($classname); - } - } - } - // Empty the object list to ensure that destructors are - // not called more than once. - $_PEAR_destructor_object_list = array(); - } - - // Now call the shutdown functions - if (isset($GLOBALS['_PEAR_shutdown_funcs']) AND is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { - foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { - call_user_func_array($value[0], $value[1]); - } - } -} - -// }}} -/** - * Standard PEAR error class for PHP 4 - * - * This class is supserseded by {@link PEAR_Exception} in PHP 5 - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Gregory Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/manual/en/core.pear.pear-error.php - * @see PEAR::raiseError(), PEAR::throwError() - * @since Class available since PHP 4.0.2 - */ -class PEAR_Error -{ - // {{{ properties - - var $error_message_prefix = ''; - var $mode = PEAR_ERROR_RETURN; - var $level = E_USER_NOTICE; - var $code = -1; - var $message = ''; - var $userinfo = ''; - var $backtrace = null; - - // }}} - // {{{ constructor - - /** - * PEAR_Error constructor - * - * @param string $message message - * - * @param int $code (optional) error code - * - * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, - * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION - * - * @param mixed $options (optional) error level, _OR_ in the case of - * PEAR_ERROR_CALLBACK, the callback function or object/method - * tuple. - * - * @param string $userinfo (optional) additional user/debug info - * - * @access public - * - */ - function PEAR_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { - if ($mode === null) { - $mode = PEAR_ERROR_RETURN; - } - $this->message = $message; - $this->code = $code; - $this->mode = $mode; - $this->userinfo = $userinfo; - - if (PEAR_ZE2) { - $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); - } else { - $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); - } - - if (!$skiptrace) { - $this->backtrace = debug_backtrace(); - if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { - unset($this->backtrace[0]['object']); - } - } - - if ($mode & PEAR_ERROR_CALLBACK) { - $this->level = E_USER_NOTICE; - $this->callback = $options; - } else { - if ($options === null) { - $options = E_USER_NOTICE; - } - - $this->level = $options; - $this->callback = null; - } - - if ($this->mode & PEAR_ERROR_PRINT) { - if (is_null($options) || is_int($options)) { - $format = "%s"; - } else { - $format = $options; - } - - printf($format, $this->getMessage()); - } - - if ($this->mode & PEAR_ERROR_TRIGGER) { - trigger_error($this->getMessage(), $this->level); - } - - if ($this->mode & PEAR_ERROR_DIE) { - $msg = $this->getMessage(); - if (is_null($options) || is_int($options)) { - $format = "%s"; - if (substr($msg, -1) != "\n") { - $msg .= "\n"; - } - } else { - $format = $options; - } - die(sprintf($format, $msg)); - } - - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_callable($this->callback)) { - call_user_func($this->callback, $this); - } - } - - if ($this->mode & PEAR_ERROR_EXCEPTION) { - trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); - eval('$e = new Exception($this->message, $this->code);throw($e);'); - } - } - - // }}} - // {{{ getMode() - - /** - * Get the error mode from an error object. - * - * @return int error mode - * @access public - */ - function getMode() { - return $this->mode; - } - - // }}} - // {{{ getCallback() - - /** - * Get the callback function/method from an error object. - * - * @return mixed callback function or object/method array - * @access public - */ - function getCallback() { - return $this->callback; - } - - // }}} - // {{{ getMessage() - - - /** - * Get the error message from an error object. - * - * @return string full error message - * @access public - */ - function getMessage() - { - return ($this->error_message_prefix . $this->message); - } - - - // }}} - // {{{ getCode() - - /** - * Get error code from an error object - * - * @return int error code - * @access public - */ - function getCode() - { - return $this->code; - } - - // }}} - // {{{ getType() - - /** - * Get the name of this error/exception. - * - * @return string error/exception name (type) - * @access public - */ - function getType() - { - return get_class($this); - } - - // }}} - // {{{ getUserInfo() - - /** - * Get additional user-supplied information. - * - * @return string user-supplied information - * @access public - */ - function getUserInfo() - { - return $this->userinfo; - } - - // }}} - // {{{ getDebugInfo() - - /** - * Get additional debug information supplied by the application. - * - * @return string debug information - * @access public - */ - function getDebugInfo() - { - return $this->getUserInfo(); - } - - // }}} - // {{{ getBacktrace() - - /** - * Get the call backtrace from where the error was generated. - * Supported with PHP 4.3.0 or newer. - * - * @param int $frame (optional) what frame to fetch - * @return array Backtrace, or NULL if not available. - * @access public - */ - function getBacktrace($frame = null) - { - if (defined('PEAR_IGNORE_BACKTRACE')) { - return null; - } - if ($frame === null) { - return $this->backtrace; - } - return $this->backtrace[$frame]; - } - - // }}} - // {{{ addUserInfo() - - function addUserInfo($info) - { - if (empty($this->userinfo)) { - $this->userinfo = $info; - } else { - $this->userinfo .= " ** $info"; - } - } - - // }}} - // {{{ toString() - function __toString() - { - return $this->getMessage(); - } - // }}} - // {{{ toString() - - /** - * Make a string representation of this object. - * - * @return string a string with an object summary - * @access public - */ - function toString() { - $modes = array(); - $levels = array(E_USER_NOTICE => 'notice', - E_USER_WARNING => 'warning', - E_USER_ERROR => 'error'); - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_array($this->callback)) { - $callback = (is_object($this->callback[0]) ? - strtolower(get_class($this->callback[0])) : - $this->callback[0]) . '::' . - $this->callback[1]; - } else { - $callback = $this->callback; - } - return sprintf('[%s: message="%s" code=%d mode=callback '. - 'callback=%s prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - $callback, $this->error_message_prefix, - $this->userinfo); - } - if ($this->mode & PEAR_ERROR_PRINT) { - $modes[] = 'print'; - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - $modes[] = 'trigger'; - } - if ($this->mode & PEAR_ERROR_DIE) { - $modes[] = 'die'; - } - if ($this->mode & PEAR_ERROR_RETURN) { - $modes[] = 'return'; - } - return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. - 'prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - implode("|", $modes), $levels[$this->level], - $this->error_message_prefix, - $this->userinfo); - } - - // }}} -} - -/* - * Local Variables: - * mode: php - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ChannelFile.php 286951 2009-08-09 14:41:22Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Needed for error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Common.php'; - -/** - * Error code if the channel.xml tag does not contain a valid version - */ -define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); -/** - * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, - * currently - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); - -/**#@+ - * Validation errors - */ -/** - * Error code when channel name is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); -/** - * Error code when channel name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); -/** - * Error code when channel summary is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); -/** - * Error code when channel summary is multi-line - */ -define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); -/** - * Error code when channel server is missing for protocol - */ -define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); -/** - * Error code when channel server is invalid for protocol - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); -/** - * Error code when a mirror name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); -/** - * Error code when a mirror type is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); -/** - * Error code when an attempt is made to generate xml, but the parsed content is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID', 23); -/** - * Error code when an empty package name validate regex is passed in - */ -define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); -/** - * Error code when a tag has no version - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); -/** - * Error code when a tag has no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); -/** - * Error code when a mirror does not exist but is called for in one of the set* - * methods. - */ -define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); -/** - * Error code when a server port is not numeric - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); -/** - * Error code when contains no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); -/** - * Error code when contains no type attribute in a protocol definition - */ -define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); -/** - * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel - */ -define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); -/** - * Error code when ssl attribute is present and is not "yes" - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); -/**#@-*/ - -/** - * Mirror types allowed. Currently only internet servers are recognized. - */ -$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); - - -/** - * The Channel handling class - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_ChannelFile -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * Supported channel.xml versions, for parsing - * @var array - * @access private - */ - var $_supportedVersions = array('1.0'); - - /** - * Parsed channel information - * @var array - * @access private - */ - var $_channelInfo; - - /** - * index into the subchannels array, used for parsing xml - * @var int - * @access private - */ - var $_subchannelIndex; - - /** - * index into the mirrors array, used for parsing xml - * @var int - * @access private - */ - var $_mirrorIndex; - - /** - * Flag used to determine the validity of parsed content - * @var boolean - * @access private - */ - var $_isValid = false; - - function PEAR_ChannelFile() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = false; - } - - /** - * @return array - * @access protected - */ - function _getErrorMessage() - { - return - array( - PEAR_CHANNELFILE_ERROR_INVALID_VERSION => - 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', - PEAR_CHANNELFILE_ERROR_NO_VERSION => - 'No version number found in tag', - PEAR_CHANNELFILE_ERROR_NO_XML_EXT => - '%error%', - PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => - 'Unable to create XML parser', - PEAR_CHANNELFILE_ERROR_PARSER_ERROR => - '%error%', - PEAR_CHANNELFILE_ERROR_NO_NAME => - 'Missing channel name', - PEAR_CHANNELFILE_ERROR_INVALID_NAME => - 'Invalid channel %tag% "%name%"', - PEAR_CHANNELFILE_ERROR_NO_SUMMARY => - 'Missing channel summary', - PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => - 'Channel summary should be on one line, but is multi-line', - PEAR_CHANNELFILE_ERROR_NO_HOST => - 'Missing channel server for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_HOST => - 'Server name "%server%" is invalid for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => - 'Invalid mirror name "%name%", mirror type %type%', - PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => - 'Invalid mirror type "%type%"', - PEAR_CHANNELFILE_ERROR_INVALID => - 'Cannot generate xml, contents are invalid', - PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => - 'packagenameregex cannot be empty', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => - '%parent% %protocol% function has no version', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => - '%parent% %protocol% function has no name', - PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => - '%parent% rest baseurl has no type', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => - 'Validation package has no name in tag', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => - 'Validation package "%package%" has no version', - PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => - 'Mirror "%mirror%" does not exist', - PEAR_CHANNELFILE_ERROR_INVALID_PORT => - 'Port "%port%" must be numeric', - PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => - ' tag must contain version attribute', - PEAR_CHANNELFILE_URI_CANT_MIRROR => - 'The __uri pseudo-channel cannot have mirrors', - PEAR_CHANNELFILE_ERROR_INVALID_SSL => - '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', - ); - } - - /** - * @param string contents of package.xml file - * @return bool success of parsing - */ - function fromXmlString($data) - { - if (preg_match('/_supportedVersions)) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', - array('version' => $channelversion[1])); - return false; - } - $parser = new PEAR_XMLParser; - $result = $parser->parse($data); - if ($result !== true) { - if ($result->getCode() == 1) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', - array('error' => $result->getMessage())); - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); - } - return false; - } - $this->_channelInfo = $parser->getData(); - return true; - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); - return false; - } - } - - /** - * @return array - */ - function toArray() - { - if (!$this->_isValid && !$this->validate()) { - return false; - } - return $this->_channelInfo; - } - - /** - * @param array - * @static - * @return PEAR_ChannelFile|false false if invalid - */ - function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') - { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - if (!$a->validate()) { - $a = false; - return $a; - } - return $a; - } - - /** - * Unlike {@link fromArray()} this does not do any validation - * @param array - * @static - * @return PEAR_ChannelFile - */ - function &fromArrayWithErrors($data, $compatibility = false, - $stackClass = 'PEAR_ErrorStack') - { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - return $a; - } - - /** - * @param array - * @access private - */ - function _fromArray($data) - { - $this->_channelInfo = $data; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getErrors($purge = false) - { - return $this->_stack->getErrors($purge); - } - - /** - * Unindent given string (?) - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } - } - return $data; - } - - /** - * Parse a channel.xml file. Expects the name of - * a channel xml file as input. - * - * @param string $descfile name of channel xml file - * @return bool success of parsing - */ - function fromXmlFile($descfile) - { - if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || - (!$fp = fopen($descfile, 'r'))) { - require_once 'phar://go-pear.phar/' . 'PEAR.php'; - return PEAR::raiseError("Unable to open $descfile"); - } - - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - return $this->fromXmlString($data); - } - - /** - * Parse channel information from different sources - * - * This method is able to extract information about a channel - * from an .xml file or a string - * - * @access public - * @param string Filename of the source or the source itself - * @return bool - */ - function fromAny($info) - { - if (is_string($info) && file_exists($info) && strlen($info) < 255) { - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = $this->fromXmlFile($info); - } else { - $fp = fopen($info, "r"); - $test = fread($fp, 5); - fclose($fp); - if ($test == "fromXmlFile($info); - } - } - if (PEAR::isError($info)) { - require_once 'phar://go-pear.phar/' . 'PEAR.php'; - return PEAR::raiseError($info); - } - } - if (is_string($info)) { - $info = $this->fromXmlString($info); - } - return $info; - } - - /** - * Return an XML document based on previous parsing and modifications - * - * @return string XML data - * - * @access public - */ - function toXml() - { - if (!$this->_isValid && !$this->validate()) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); - return false; - } - if (!isset($this->_channelInfo['attribs']['version'])) { - $this->_channelInfo['attribs']['version'] = '1.0'; - } - $channelInfo = $this->_channelInfo; - $ret = "\n"; - $ret .= " - $channelInfo[name] - " . htmlspecialchars($channelInfo['summary'])." -"; - if (isset($channelInfo['suggestedalias'])) { - $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; - } - if (isset($channelInfo['validatepackage'])) { - $ret .= ' ' . - htmlspecialchars($channelInfo['validatepackage']['_content']) . - "\n"; - } - $ret .= " \n"; - $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); - } - $ret .= " \n"; - if (isset($channelInfo['servers']['mirror'])) { - $ret .= $this->_makeMirrorsXml($channelInfo); - } - $ret .= " \n"; - $ret .= ""; - return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); - } - - /** - * Generate the tag - * @access private - */ - function _makeRestXml($info, $indent) - { - $ret = $indent . "\n"; - if (isset($info['baseurl']) && !isset($info['baseurl'][0])) { - $info['baseurl'] = array($info['baseurl']); - } - - if (isset($info['baseurl'])) { - foreach ($info['baseurl'] as $url) { - $ret .= "$indent \n"; - } - } - $ret .= $indent . "\n"; - return $ret; - } - - /** - * Generate the tag - * @access private - */ - function _makeMirrorsXml($channelInfo) - { - $ret = ""; - if (!isset($channelInfo['servers']['mirror'][0])) { - $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); - } - foreach ($channelInfo['servers']['mirror'] as $mirror) { - $ret .= ' _makeRestXml($mirror['rest'], ' '); - } - $ret .= " \n"; - } else { - $ret .= "/>\n"; - } - } - return $ret; - } - - /** - * Generate the tag - * @access private - */ - function _makeFunctionsXml($functions, $indent, $rest = false) - { - $ret = ''; - if (!isset($functions[0])) { - $functions = array($functions); - } - foreach ($functions as $function) { - $ret .= "$indent\n"; - } - return $ret; - } - - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params); - $this->_isValid = false; - } - - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params); - } - - /** - * Validate parsed file. - * - * @access public - * @return boolean - */ - function validate() - { - $this->_isValid = true; - $info = $this->_channelInfo; - if (empty($info['name'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); - } elseif (!$this->validChannelServer($info['name'])) { - if ($info['name'] != '__uri') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', - 'name' => $info['name'])); - } - } - if (empty($info['summary'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (isset($info['suggestedalias'])) { - if (!$this->validChannelServer($info['suggestedalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); - } - } - if (isset($info['localalias'])) { - if (!$this->validChannelServer($info['localalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'localalias', 'name' =>$info['localalias'])); - } - } - if (isset($info['validatepackage'])) { - if (!isset($info['validatepackage']['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); - } - if (!isset($info['validatepackage']['attribs']['version'])) { - $content = isset($info['validatepackage']['_content']) ? - $info['validatepackage']['_content'] : - null; - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, - array('package' => $content)); - } - } - - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && - !is_numeric($info['servers']['primary']['attribs']['port'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, - array('port' => $info['servers']['primary']['attribs']['port'])); - } - - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && - $info['servers']['primary']['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['servers']['primary']['attribs']['ssl'], - 'server' => $info['name'])); - } - - if (isset($info['servers']['primary']['rest']) && - isset($info['servers']['primary']['rest']['baseurl'])) { - $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); - } - if (isset($info['servers']['mirror'])) { - if ($this->_channelInfo['name'] == '__uri') { - $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); - } - if (!isset($info['servers']['mirror'][0])) { - $info['servers']['mirror'] = array($info['servers']['mirror']); - } - foreach ($info['servers']['mirror'] as $mirror) { - if (!isset($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, - array('type' => 'mirror')); - } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, - array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); - } - if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); - } - if (isset($mirror['rest'])) { - $this->_validateFunctions('rest', $mirror['rest']['baseurl'], - $mirror['attribs']['host']); - } - } - } - return $this->_isValid; - } - - /** - * @param string rest - protocol name this function applies to - * @param array the functions - * @param string the name of the parent element (mirror name, for instance) - */ - function _validateFunctions($protocol, $functions, $parent = '') - { - if (!isset($functions[0])) { - $functions = array($functions); - } - - foreach ($functions as $function) { - if (!isset($function['_content']) || empty($function['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, - array('parent' => $parent, 'protocol' => $protocol)); - } - - if ($protocol == 'rest') { - if (!isset($function['attribs']['type']) || - empty($function['attribs']['type'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE, - array('parent' => $parent, 'protocol' => $protocol)); - } - } else { - if (!isset($function['attribs']['version']) || - empty($function['attribs']['version'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, - array('parent' => $parent, 'protocol' => $protocol)); - } - } - } - } - - /** - * Test whether a string contains a valid channel server. - * @param string $ver the package version to test - * @return bool - */ - function validChannelServer($server) - { - if ($server == '__uri') { - return true; - } - return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); - } - - /** - * @return string|false - */ - function getName() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; - } - - return false; - } - - /** - * @return string|false - */ - function getServer() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; - } - - return false; - } - - /** - * @return int|80 port number to connect to - */ - function getPort($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['port'])) { - return $mir['attribs']['port']; - } - - if ($this->getSSL($mirror)) { - return 443; - } - - return 80; - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { - return $this->_channelInfo['servers']['primary']['attribs']['port']; - } - - if ($this->getSSL()) { - return 443; - } - - return 80; - } - - /** - * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel - */ - function getSSL($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['ssl'])) { - return true; - } - - return false; - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - return true; - } - - return false; - } - - /** - * @return string|false - */ - function getSummary() - { - if (isset($this->_channelInfo['summary'])) { - return $this->_channelInfo['summary']; - } - - return false; - } - - /** - * @param string protocol type - * @param string Mirror name - * @return array|false - */ - function getFunctions($protocol, $mirror = false) - { - if ($this->getName() == '__uri') { - return false; - } - - $function = $protocol == 'rest' ? 'baseurl' : 'function'; - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir[$protocol][$function])) { - return $mir[$protocol][$function]; - } - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { - return $this->_channelInfo['servers']['primary'][$protocol][$function]; - } - - return false; - } - - /** - * @param string Protocol type - * @param string Function name (null to return the - * first protocol of the type requested) - * @param string Mirror name, if any - * @return array - */ - function getFunction($type, $name = null, $mirror = false) - { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } - - foreach ($protocols as $protocol) { - if ($name === null) { - return $protocol; - } - - if ($protocol['_content'] != $name) { - continue; - } - - return $protocol; - } - - return false; - } - - /** - * @param string protocol type - * @param string protocol name - * @param string version - * @param string mirror name - * @return boolean - */ - function supports($type, $name = null, $mirror = false, $version = '1.0') - { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } - - foreach ($protocols as $protocol) { - if ($protocol['attribs']['version'] != $version) { - continue; - } - - if ($name === null) { - return true; - } - - if ($protocol['_content'] != $name) { - continue; - } - - return true; - } - - return false; - } - - /** - * Determines whether a channel supports Representational State Transfer (REST) protocols - * for retrieving channel information - * @param string - * @return bool - */ - function supportsREST($mirror = false) - { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; - } - - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - return isset($mir['rest']); - } - - return false; - } - - return isset($this->_channelInfo['servers']['primary']['rest']); - } - - /** - * Get the URL to access a base resource. - * - * Hyperlinks in the returned xml will be used to retrieve the proper information - * needed. This allows extreme extensibility and flexibility in implementation - * @param string Resource Type to retrieve - */ - function getBaseURL($resourceType, $mirror = false) - { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; - } - - if ($mirror) { - $mir = $this->getMirror($mirror); - if (!$mir) { - return false; - } - - $rest = $mir['rest']; - } else { - $rest = $this->_channelInfo['servers']['primary']['rest']; - } - - if (!isset($rest['baseurl'][0])) { - $rest['baseurl'] = array($rest['baseurl']); - } - - foreach ($rest['baseurl'] as $baseurl) { - if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { - return $baseurl['_content']; - } - } - - return false; - } - - /** - * Since REST does not implement RPC, provide this as a logical wrapper around - * resetFunctions for REST - * @param string|false mirror name, if any - */ - function resetREST($mirror = false) - { - return $this->resetFunctions('rest', $mirror); - } - - /** - * Empty all protocol definitions - * @param string protocol type - * @param string|false mirror name, if any - */ - function resetFunctions($type, $mirror = false) - { - if ($mirror) { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); - } - - foreach ($mirrors as $i => $mir) { - if ($mir['attribs']['host'] == $mirror) { - if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { - unset($this->_channelInfo['servers']['mirror'][$i][$type]); - } - - return true; - } - } - - return false; - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary'][$type])) { - unset($this->_channelInfo['servers']['primary'][$type]); - } - - return true; - } - - /** - * Set a channel's protocols to the protocols supported by pearweb - */ - function setDefaultPEARProtocols($version = '1.0', $mirror = false) - { - switch ($version) { - case '1.0' : - $this->resetREST($mirror); - - if (!isset($this->_channelInfo['servers'])) { - $this->_channelInfo['servers'] = array('primary' => - array('rest' => array())); - } elseif (!isset($this->_channelInfo['servers']['primary'])) { - $this->_channelInfo['servers']['primary'] = array('rest' => array()); - } - - return true; - break; - default : - return false; - break; - } - } - - /** - * @return array - */ - function getMirrors() - { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); - } - - return $mirrors; - } - - return array(); - } - - /** - * Get the unserialized XML representing a mirror - * @return array|false - */ - function getMirror($server) - { - foreach ($this->getMirrors() as $mirror) { - if ($mirror['attribs']['host'] == $server) { - return $mirror; - } - } - - return false; - } - - /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_NAME - * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME - */ - function setName($name) - { - return $this->setServer($name); - } - - /** - * Set the socket number (port) that is used to connect to this channel - * @param integer - * @param string|false name of the mirror server, or false for the primary - */ - function setPort($port, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; - return true; - } - } - - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; - $this->_isValid = false; - return true; - } - } - - $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; - $this->_isValid = false; - return true; - } - - /** - * Set the socket number (port) that is used to connect to this channel - * @param bool Determines whether to turn on SSL support or turn it off - * @param string|false name of the mirror server, or false for the primary - */ - function setSSL($ssl = true, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror'][$i] - ['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); - } - } else { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; - } - - return true; - } - } - - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); - } - } else { - $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; - } - - $this->_isValid = false; - return true; - } - } - - if ($ssl) { - $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; - } else { - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); - } - } - - $this->_isValid = false; - return true; - } - - /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_SERVER - * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER - */ - function setServer($server, $mirror = false) - { - if (empty($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); - return false; - } elseif (!$this->validChannelServer($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'name', 'name' => $server)); - return false; - } - - if ($mirror) { - $found = false; - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $found = true; - break; - } - } - - if (!$found) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; - return true; - } - - $this->_channelInfo['name'] = $server; - return true; - } - - /** - * @param string - * @return boolean success - * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY - * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY - */ - function setSummary($summary) - { - if (empty($summary)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - return false; - } elseif (strpos(trim($summary), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $summary)); - } - - $this->_channelInfo['summary'] = $summary; - return true; - } - - /** - * @param string - * @param boolean determines whether the alias is in channel.xml or local - * @return boolean success - */ - function setAlias($alias, $local = false) - { - if (!$this->validChannelServer($alias)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' => $alias)); - return false; - } - - if ($local) { - $this->_channelInfo['localalias'] = $alias; - } else { - $this->_channelInfo['suggestedalias'] = $alias; - } - - return true; - } - - /** - * @return string - */ - function getAlias() - { - if (isset($this->_channelInfo['localalias'])) { - return $this->_channelInfo['localalias']; - } - if (isset($this->_channelInfo['suggestedalias'])) { - return $this->_channelInfo['suggestedalias']; - } - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; - } - return ''; - } - - /** - * Set the package validation object if it differs from PEAR's default - * The class must be includeable via changing _ in the classname to path separator, - * but no checking of this is made. - * @param string|false pass in false to reset to the default packagename regex - * @return boolean success - */ - function setValidationPackage($validateclass, $version) - { - if (empty($validateclass)) { - unset($this->_channelInfo['validatepackage']); - } - $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); - $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); - } - - /** - * Add a protocol to the provides section - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - * @param string mirror name, if this is a mirror's protocol - * @return bool - */ - function addFunction($type, $version, $name = '', $mirror = false) - { - if ($mirror) { - return $this->addMirrorFunction($mirror, $type, $version, $name); - } - - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { - if (!isset($this->_channelInfo['servers'])) { - $this->_channelInfo['servers'] = array('primary' => - array($type => array())); - } elseif (!isset($this->_channelInfo['servers']['primary'])) { - $this->_channelInfo['servers']['primary'] = array($type => array()); - } - - $this->_channelInfo['servers']['primary'][$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { - $this->_channelInfo['servers']['primary'][$type]['function'] = array( - $this->_channelInfo['servers']['primary'][$type]['function']); - } - - $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; - return true; - } - /** - * Add a protocol to a mirror's provides section - * @param string mirror name (server) - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - */ - function addMirrorFunction($mirror, $type, $version, $name = '') - { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; - } - } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; - } - } - - if (!$setmirror) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($setmirror[$type]['function'])) { - $setmirror[$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror[$type]['function'][0])) { - $setmirror[$type]['function'] = array($setmirror[$type]['function']); - } - - $setmirror[$type]['function'][] = $set; - $this->_isValid = false; - return true; - } - - /** - * @param string Resource Type this url links to - * @param string URL - * @param string|false mirror name, if this is not a primary server REST base URL - */ - function setBaseURL($resourceType, $url, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; - } - } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; - } - } - } else { - $setmirror = &$this->_channelInfo['servers']['primary']; - } - - $set = array('attribs' => array('type' => $resourceType), '_content' => $url); - if (!isset($setmirror['rest'])) { - $setmirror['rest'] = array(); - } - - if (!isset($setmirror['rest']['baseurl'])) { - $setmirror['rest']['baseurl'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror['rest']['baseurl'][0])) { - $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); - } - - foreach ($setmirror['rest']['baseurl'] as $i => $url) { - if ($url['attribs']['type'] == $resourceType) { - $this->_isValid = false; - $setmirror['rest']['baseurl'][$i] = $set; - return true; - } - } - - $setmirror['rest']['baseurl'][] = $set; - $this->_isValid = false; - return true; - } - - /** - * @param string mirror server - * @param int mirror http port - * @return boolean - */ - function addMirror($server, $port = null) - { - if ($this->_channelInfo['name'] == '__uri') { - return false; // the __uri channel cannot have mirrors by definition - } - - $set = array('attribs' => array('host' => $server)); - if (is_numeric($port)) { - $set['attribs']['port'] = $port; - } - - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_channelInfo['servers']['mirror'] = $set; - return true; - } - - if (!isset($this->_channelInfo['servers']['mirror'][0])) { - $this->_channelInfo['servers']['mirror'] = - array($this->_channelInfo['servers']['mirror']); - } - - $this->_channelInfo['servers']['mirror'][] = $set; - return true; - } - - /** - * Retrieve the name of the validation package for this channel - * @return string|false - */ - function getValidationPackage() - { - if (!$this->_isValid && !$this->validate()) { - return false; - } - - if (!isset($this->_channelInfo['validatepackage'])) { - return array('attribs' => array('version' => 'default'), - '_content' => 'PEAR_Validate'); - } - - return $this->_channelInfo['validatepackage']; - } - - /** - * Retrieve the object that can be used for custom validation - * @param string|false the name of the package to validate. If the package is - * the channel validation package, PEAR_Validate is returned - * @return PEAR_Validate|false false is returned if the validation package - * cannot be located - */ - function &getValidationObject($package = false) - { - if (!class_exists('PEAR_Validate')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php'; - } - - if (!$this->_isValid) { - if (!$this->validate()) { - $a = false; - return $a; - } - } - - if (isset($this->_channelInfo['validatepackage'])) { - if ($package == $this->_channelInfo['validatepackage']) { - // channel validation packages are always validated by PEAR_Validate - $val = &new PEAR_Validate; - return $val; - } - - if (!class_exists(str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']))) { - if ($this->isIncludeable(str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php')) { - include_once 'phar://go-pear.phar/' . str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php'; - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; - } else { - $a = false; - return $a; - } - } else { - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; - } - } else { - $val = &new PEAR_Validate; - } - - return $val; - } - - function isIncludeable($path) - { - $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($possibilities as $dir) { - if (file_exists($dir . DIRECTORY_SEPARATOR . $path) - && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { - return true; - } - } - - return false; - } - - /** - * This function is used by the channel updater and retrieves a value set by - * the registry, or the current time if it has not been set - * @return string - */ - function lastModified() - { - if (isset($this->_channelInfo['_lastmodified'])) { - return $this->_channelInfo['_lastmodified']; - } - - return time(); - } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Parser.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base xml parser class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; -/** - * Parser for channel.xml - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_ChannelFile_Parser extends PEAR_XMLParser -{ - var $_config; - var $_logger; - var $_registry; - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - function parse($data, $file) - { - if (PEAR::isError($err = parent::parse($data, $file))) { - return $err; - } - - $ret = new PEAR_ChannelFile; - $ret->setConfig($this->_config); - if (isset($this->_logger)) { - $ret->setLogger($this->_logger); - } - - $ret->fromArray($this->_unserializedData); - // make sure the filelist is in the easy to read format needed - $ret->flattenFilelist(); - $ret->setPackagefile($file, $archive); - return $ret; - } -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Command.php 286494 2009-07-29 06:57:11Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Needed for error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php'; - -/** - * List of commands and what classes they are implemented in. - * @var array command => implementing class - */ -$GLOBALS['_PEAR_Command_commandlist'] = array(); - -/** - * List of commands and their descriptions - * @var array command => description - */ -$GLOBALS['_PEAR_Command_commanddesc'] = array(); - -/** - * List of shortcuts to common commands. - * @var array shortcut => command - */ -$GLOBALS['_PEAR_Command_shortcuts'] = array(); - -/** - * Array of command objects - * @var array class => object - */ -$GLOBALS['_PEAR_Command_objects'] = array(); - -/** - * PEAR command class, a simple factory class for administrative - * commands. - * - * How to implement command classes: - * - * - The class must be called PEAR_Command_Nnn, installed in the - * "PEAR/Common" subdir, with a method called getCommands() that - * returns an array of the commands implemented by the class (see - * PEAR/Command/Install.php for an example). - * - * - The class must implement a run() function that is called with three - * params: - * - * (string) command name - * (array) assoc array with options, freely defined by each - * command, for example: - * array('force' => true) - * (array) list of the other parameters - * - * The run() function returns a PEAR_CommandResponse object. Use - * these methods to get information: - * - * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) - * *_PARTIAL means that you need to issue at least - * one more command to complete the operation - * (used for example for validation steps). - * - * string getMessage() Returns a message for the user. Remember, - * no HTML or other interface-specific markup. - * - * If something unexpected happens, run() returns a PEAR error. - * - * - DON'T OUTPUT ANYTHING! Return text for output instead. - * - * - DON'T USE HTML! The text you return will be used from both Gtk, - * web and command-line interfaces, so for now, keep everything to - * plain text. - * - * - DON'T USE EXIT OR DIE! Always use pear errors. From static - * classes do PEAR::raiseError(), from other classes do - * $this->raiseError(). - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command -{ - // {{{ factory() - - /** - * Get the right object for executing a command. - * - * @param string $command The name of the command - * @param object $config Instance of PEAR_Config object - * - * @return object the command object or a PEAR error - * - * @access public - * @static - */ - function &factory($command, &$config) - { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; - } - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; - } - if (!class_exists($class)) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; - } - $ui =& PEAR_Command::getFrontendObject(); - $obj = &new $class($ui, $config); - return $obj; - } - - // }}} - // {{{ & getObject() - function &getObject($command) - { - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; - } - if (!class_exists($class)) { - return PEAR::raiseError("unknown command `$command'"); - } - $ui =& PEAR_Command::getFrontendObject(); - $config = &PEAR_Config::singleton(); - $obj = &new $class($ui, $config); - return $obj; - } - - // }}} - // {{{ & getFrontendObject() - - /** - * Get instance of frontend object. - * - * @return object|PEAR_Error - * @static - */ - function &getFrontendObject() - { - $a = &PEAR_Frontend::singleton(); - return $a; - } - - // }}} - // {{{ & setFrontendClass() - - /** - * Load current frontend class. - * - * @param string $uiclass Name of class implementing the frontend - * - * @return object the frontend object, or a PEAR error - * @static - */ - function &setFrontendClass($uiclass) - { - $a = &PEAR_Frontend::setFrontendClass($uiclass); - return $a; - } - - // }}} - // {{{ setFrontendType() - - /** - * Set current frontend. - * - * @param string $uitype Name of the frontend type (for example "CLI") - * - * @return object the frontend object, or a PEAR error - * @static - */ - function setFrontendType($uitype) - { - $uiclass = 'PEAR_Frontend_' . $uitype; - return PEAR_Command::setFrontendClass($uiclass); - } - - // }}} - // {{{ registerCommands() - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * - * @param bool (optional) if FALSE (default), the new list of - * commands should replace the current one. If TRUE, - * new entries will be merged with old. - * - * @param string (optional) where (what directory) to look for - * classes, defaults to the Command subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * - * @access public - * @static - */ - function registerCommands($merge = false, $dir = null) - { - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Command'; - } - if (!is_dir($dir)) { - return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); - } - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerCommands: opendir($dir) failed"); - } - if (!$merge) { - $GLOBALS['_PEAR_Command_commandlist'] = array(); - } - - while ($file = readdir($dp)) { - if ($file{0} == '.' || substr($file, -4) != '.xml') { - continue; - } - - $f = substr($file, 0, -4); - $class = "PEAR_Command_" . $f; - // List of commands - if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { - $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php'; - } - - $parser->parse(file_get_contents("$dir/$file")); - $implements = $parser->getData(); - foreach ($implements as $command => $desc) { - if ($command == 'attribs') { - continue; - } - - if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return PEAR::raiseError('Command "' . $command . '" already registered in ' . - 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - - $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; - $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; - if (isset($desc['shortcut'])) { - $shortcut = $desc['shortcut']; - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { - return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . - 'registered to command "' . $command . '" in class "' . - $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; - } - - if (isset($desc['options']) && $desc['options']) { - foreach ($desc['options'] as $oname => $option) { - if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { - return PEAR::raiseError('Option "' . $oname . '" short option "' . - $option['shortopt'] . '" must be ' . - 'only 1 character in Command "' . $command . '" in class "' . - $class . '"'); - } - } - } - } - } - - ksort($GLOBALS['_PEAR_Command_shortcuts']); - ksort($GLOBALS['_PEAR_Command_commandlist']); - @closedir($dp); - return true; - } - - // }}} - // {{{ getCommands() - - /** - * Get the list of currently supported commands, and what - * classes implement them. - * - * @return array command => implementing class - * - * @access public - * @static - */ - function getCommands() - { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - return $GLOBALS['_PEAR_Command_commandlist']; - } - - // }}} - // {{{ getShortcuts() - - /** - * Get the list of command shortcuts. - * - * @return array shortcut => command - * - * @access public - * @static - */ - function getShortcuts() - { - if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { - PEAR_Command::registerCommands(); - } - return $GLOBALS['_PEAR_Command_shortcuts']; - } - - // }}} - // {{{ getGetoptArgs() - - /** - * Compiles arguments for getopt. - * - * @param string $command command to get optstring for - * @param string $short_args (reference) short getopt format - * @param array $long_args (reference) long getopt format - * - * @return void - * - * @access public - * @static - */ - function getGetoptArgs($command, &$short_args, &$long_args) - { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return null; - } - $obj = &PEAR_Command::getObject($command); - return $obj->getGetoptArgs($command, $short_args, $long_args); - } - - // }}} - // {{{ getDescription() - - /** - * Get description for a command. - * - * @param string $command Name of the command - * - * @return string command description - * - * @access public - * @static - */ - function getDescription($command) - { - if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { - return null; - } - return $GLOBALS['_PEAR_Command_commanddesc'][$command]; - } - - // }}} - // {{{ getHelp() - - /** - * Get help for command. - * - * @param string $command Name of the command to return help for - * - * @access public - * @static - */ - function getHelp($command) - { - $cmds = PEAR_Command::getCommands(); - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (isset($cmds[$command])) { - $obj = &PEAR_Command::getObject($command); - return $obj->getHelp($command); - } - return false; - } - // }}} -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; - -/** - * PEAR commands base class - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Common extends PEAR -{ - /** - * PEAR_Config object used to pass user system and configuration - * on when executing commands - * - * @var PEAR_Config - */ - var $config; - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * User Interface object, for all interaction with the user. - * @var object - */ - var $ui; - - var $_deps_rel_trans = array( - 'lt' => '<', - 'le' => '<=', - 'eq' => '=', - 'ne' => '!=', - 'gt' => '>', - 'ge' => '>=', - 'has' => '==' - ); - - var $_deps_type_trans = array( - 'pkg' => 'package', - 'ext' => 'extension', - 'php' => 'PHP', - 'prog' => 'external program', - 'ldlib' => 'external library for linking', - 'rtlib' => 'external runtime library', - 'os' => 'operating system', - 'websrv' => 'web server', - 'sapi' => 'SAPI backend' - ); - - /** - * PEAR_Command_Common constructor. - * - * @access public - */ - function PEAR_Command_Common(&$ui, &$config) - { - parent::PEAR(); - $this->config = &$config; - $this->ui = &$ui; - } - - /** - * Return a list of all the commands defined by this class. - * @return array list of commands - * @access public - */ - function getCommands() - { - $ret = array(); - foreach (array_keys($this->commands) as $command) { - $ret[$command] = $this->commands[$command]['summary']; - } - - return $ret; - } - - /** - * Return a list of all the command shortcuts defined by this class. - * @return array shortcut => command - * @access public - */ - function getShortcuts() - { - $ret = array(); - foreach (array_keys($this->commands) as $command) { - if (isset($this->commands[$command]['shortcut'])) { - $ret[$this->commands[$command]['shortcut']] = $command; - } - } - - return $ret; - } - - function getOptions($command) - { - $shortcuts = $this->getShortcuts(); - if (isset($shortcuts[$command])) { - $command = $shortcuts[$command]; - } - - if (isset($this->commands[$command]) && - isset($this->commands[$command]['options'])) { - return $this->commands[$command]['options']; - } - - return null; - } - - function getGetoptArgs($command, &$short_args, &$long_args) - { - $short_args = ''; - $long_args = array(); - if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) { - return; - } - - reset($this->commands[$command]['options']); - while (list($option, $info) = each($this->commands[$command]['options'])) { - $larg = $sarg = ''; - if (isset($info['arg'])) { - if ($info['arg']{0} == '(') { - $larg = '=='; - $sarg = '::'; - $arg = substr($info['arg'], 1, -1); - } else { - $larg = '='; - $sarg = ':'; - $arg = $info['arg']; - } - } - - if (isset($info['shortopt'])) { - $short_args .= $info['shortopt'] . $sarg; - } - - $long_args[] = $option . $larg; - } - } - - /** - * Returns the help message for the given command - * - * @param string $command The command - * @return mixed A fail string if the command does not have help or - * a two elements array containing [0]=>help string, - * [1]=> help string for the accepted cmd args - */ - function getHelp($command) - { - $config = &PEAR_Config::singleton(); - if (!isset($this->commands[$command])) { - return "No such command \"$command\""; - } - - $help = null; - if (isset($this->commands[$command]['doc'])) { - $help = $this->commands[$command]['doc']; - } - - if (empty($help)) { - // XXX (cox) Fallback to summary if there is no doc (show both?) - if (!isset($this->commands[$command]['summary'])) { - return "No help for command \"$command\""; - } - $help = $this->commands[$command]['summary']; - } - - if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { - foreach($matches[0] as $k => $v) { - $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); - } - } - - return array($help, $this->getHelpArgs($command)); - } - - /** - * Returns the help for the accepted arguments of a command - * - * @param string $command - * @return string The help string - */ - function getHelpArgs($command) - { - if (isset($this->commands[$command]['options']) && - count($this->commands[$command]['options'])) - { - $help = "Options:\n"; - foreach ($this->commands[$command]['options'] as $k => $v) { - if (isset($v['arg'])) { - if ($v['arg'][0] == '(') { - $arg = substr($v['arg'], 1, -1); - $sapp = " [$arg]"; - $lapp = "[=$arg]"; - } else { - $sapp = " $v[arg]"; - $lapp = "=$v[arg]"; - } - } else { - $sapp = $lapp = ""; - } - - if (isset($v['shortopt'])) { - $s = $v['shortopt']; - $help .= " -$s$sapp, --$k$lapp\n"; - } else { - $help .= " --$k$lapp\n"; - } - - $p = " "; - $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); - $help .= " $doc\n"; - } - - return $help; - } - - return null; - } - - function run($command, $options, $params) - { - if (empty($this->commands[$command]['function'])) { - // look for shortcuts - foreach (array_keys($this->commands) as $cmd) { - if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) { - if (empty($this->commands[$cmd]['function'])) { - return $this->raiseError("unknown command `$command'"); - } else { - $func = $this->commands[$cmd]['function']; - } - $command = $cmd; - - //$command = $this->commands[$cmd]['function']; - break; - } - } - } else { - $func = $this->commands[$command]['function']; - } - - return $this->$func($command, $options, $params); - } -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Install.php 287477 2009-08-19 14:19:43Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Command/Common.php'; - -/** - * PEAR commands for installation or deinstallation/upgrading of - * packages. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Install extends PEAR_Command_Common -{ - // {{{ properties - - var $commands = array( - 'install' => array( - 'summary' => 'Install Package', - 'function' => 'doInstall', - 'shortcut' => 'i', - 'options' => array( - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'will overwrite newer installed packages', - ), - 'loose' => array( - 'shortopt' => 'l', - 'doc' => 'do not check for recommended dependency version', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, install anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as installed', - ), - 'soft' => array( - 'shortopt' => 's', - 'doc' => 'soft install, fail silently, or upgrade if already installed', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', - ), - 'packagingroot' => array( - 'shortopt' => 'P', - 'arg' => 'DIR', - 'doc' => 'root directory used when packaging files, like RPM packaging', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'alldeps' => array( - 'shortopt' => 'a', - 'doc' => 'install all required and optional dependencies', - ), - 'onlyreqdeps' => array( - 'shortopt' => 'o', - 'doc' => 'install all required dependencies', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to download any urls or contact channels', - ), - 'pretend' => array( - 'shortopt' => 'p', - 'doc' => 'Only list the packages that would be downloaded', - ), - ), - 'doc' => '[channel/] ... -Installs one or more PEAR packages. You can specify a package to -install in four ways: - -"Package-1.0.tgz" : installs from a local file - -"http://example.com/Package-1.0.tgz" : installs from -anywhere on the net. - -"package.xml" : installs the package described in -package.xml. Useful for testing, or for wrapping a PEAR package in -another package manager such as RPM. - -"Package[-version/state][.tar]" : queries your default channel\'s server -({config master_server}) and downloads the newest package with -the preferred quality/state ({config preferred_state}). - -To retrieve Package version 1.1, use "Package-1.1," to retrieve -Package state beta, use "Package-beta." To retrieve an uncompressed -file, append .tar (make sure there is no file by the same name first) - -To download a package from another channel, prefix with the channel name like -"channel/Package" - -More than one package may be specified at once. It is ok to mix these -four ways of specifying packages. -'), - 'upgrade' => array( - 'summary' => 'Upgrade Package', - 'function' => 'doInstall', - 'shortcut' => 'up', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'upgrade packages from a specific channel', - 'arg' => 'CHAN', - ), - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'overwrite newer installed packages', - ), - 'loose' => array( - 'shortopt' => 'l', - 'doc' => 'do not check for recommended dependency version', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, upgrade anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as upgraded', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'alldeps' => array( - 'shortopt' => 'a', - 'doc' => 'install all required and optional dependencies', - ), - 'onlyreqdeps' => array( - 'shortopt' => 'o', - 'doc' => 'install all required dependencies', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to download any urls or contact channels', - ), - 'pretend' => array( - 'shortopt' => 'p', - 'doc' => 'Only list the packages that would be downloaded', - ), - ), - 'doc' => ' ... -Upgrades one or more PEAR packages. See documentation for the -"install" command for ways to specify a package. - -When upgrading, your package will be updated if the provided new -package has a higher version number (use the -f option if you need to -upgrade anyway). - -More than one package may be specified at once. -'), - 'upgrade-all' => array( - 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]', - 'function' => 'doUpgradeAll', - 'shortcut' => 'ua', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'upgrade packages from a specific channel', - 'arg' => 'CHAN', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, upgrade anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as upgraded', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'loose' => array( - 'doc' => 'do not check for recommended dependency version', - ), - ), - 'doc' => ' -WARNING: This function is deprecated in favor of using the upgrade command with no params - -Upgrades all packages that have a newer release available. Upgrades are -done only if there is a release available of the state specified in -"preferred_state" (currently {config preferred_state}), or a state considered -more stable. -'), - 'uninstall' => array( - 'summary' => 'Un-install Package', - 'function' => 'doUninstall', - 'shortcut' => 'un', - 'options' => array( - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, uninstall anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not remove files, only register the packages as not installed', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to uninstall remotely', - ), - ), - 'doc' => '[channel/] ... -Uninstalls one or more PEAR packages. More than one package may be -specified at once. Prefix with channel name to uninstall from a -channel not in your default channel ({config default_channel}) -'), - 'bundle' => array( - 'summary' => 'Unpacks a Pecl Package', - 'function' => 'doBundle', - 'shortcut' => 'bun', - 'options' => array( - 'destination' => array( - 'shortopt' => 'd', - 'arg' => 'DIR', - 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', - ), - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'Force the unpacking even if there were errors in the package', - ), - ), - 'doc' => ' -Unpacks a Pecl Package into the selected location. It will download the -package if needed. -'), - 'run-scripts' => array( - 'summary' => 'Run Post-Install Scripts bundled with a package', - 'function' => 'doRunScripts', - 'shortcut' => 'rs', - 'options' => array( - ), - 'doc' => ' -Run post-installation scripts in package , if any exist. -'), - ); - - // }}} - // {{{ constructor - - /** - * PEAR_Command_Install constructor. - * - * @access public - */ - function PEAR_Command_Install(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - // }}} - - /** - * For unit testing purposes - */ - function &getDownloader(&$ui, $options, &$config) - { - if (!class_exists('PEAR_Downloader')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php'; - } - $a = &new PEAR_Downloader($ui, $options, $config); - return $a; - } - - /** - * For unit testing purposes - */ - function &getInstaller(&$ui) - { - if (!class_exists('PEAR_Installer')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Installer.php'; - } - $a = &new PEAR_Installer($ui); - return $a; - } - - function enableExtension($binaries, $type) - { - if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { - return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); - } - $ini = $this->_parseIni($phpini); - if (PEAR::isError($ini)) { - return $ini; - } - $line = 0; - if ($type == 'extsrc' || $type == 'extbin') { - $search = 'extensions'; - $enable = 'extension'; - } else { - $search = 'zend_extensions'; - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $enable = 'zend_extension' . $debug . $ts; - } - foreach ($ini[$search] as $line => $extension) { - if (in_array($extension, $binaries, true) || in_array( - $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { - // already enabled - assume if one is, all are - return true; - } - } - if ($line) { - $newini = array_slice($ini['all'], 0, $line); - } else { - $newini = array(); - } - foreach ($binaries as $binary) { - if ($ini['extension_dir']) { - $binary = basename($binary); - } - $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n"); - } - $newini = array_merge($newini, array_slice($ini['all'], $line)); - $fp = @fopen($phpini, 'wb'); - if (!$fp) { - return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); - } - foreach ($newini as $line) { - fwrite($fp, $line); - } - fclose($fp); - return true; - } - - function disableExtension($binaries, $type) - { - if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { - return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); - } - $ini = $this->_parseIni($phpini); - if (PEAR::isError($ini)) { - return $ini; - } - $line = 0; - if ($type == 'extsrc' || $type == 'extbin') { - $search = 'extensions'; - $enable = 'extension'; - } else { - $search = 'zend_extensions'; - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $enable = 'zend_extension' . $debug . $ts; - } - $found = false; - foreach ($ini[$search] as $line => $extension) { - if (in_array($extension, $binaries, true) || in_array( - $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { - $found = true; - break; - } - } - if (!$found) { - // not enabled - return true; - } - $fp = @fopen($phpini, 'wb'); - if (!$fp) { - return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); - } - if ($line) { - $newini = array_slice($ini['all'], 0, $line); - // delete the enable line - $newini = array_merge($newini, array_slice($ini['all'], $line + 1)); - } else { - $newini = array_slice($ini['all'], 1); - } - foreach ($newini as $line) { - fwrite($fp, $line); - } - fclose($fp); - return true; - } - - function _parseIni($filename) - { - if (!file_exists($filename)) { - return PEAR::raiseError('php.ini "' . $filename . '" does not exist'); - } - - if (filesize($filename) > 300000) { - return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting'); - } - - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; - $zend_extension_line = 'zend_extension' . $debug . $ts; - $all = @file($filename); - if (!$all) { - return PEAR::raiseError('php.ini "' . $filename .'" could not be read'); - } - $zend_extensions = $extensions = array(); - // assume this is right, but pull from the php.ini if it is found - $extension_dir = ini_get('extension_dir'); - foreach ($all as $linenum => $line) { - $line = trim($line); - if (!$line) { - continue; - } - if ($line[0] == ';') { - continue; - } - if (strtolower(substr($line, 0, 13)) == 'extension_dir') { - $line = trim(substr($line, 13)); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $extension_dir = str_replace('"', '', array_shift($x)); - continue; - } - } - if (strtolower(substr($line, 0, 9)) == 'extension') { - $line = trim(substr($line, 9)); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $extensions[$linenum] = str_replace('"', '', array_shift($x)); - continue; - } - } - if (strtolower(substr($line, 0, strlen($zend_extension_line))) == - $zend_extension_line) { - $line = trim(substr($line, strlen($zend_extension_line))); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $zend_extensions[$linenum] = str_replace('"', '', array_shift($x)); - continue; - } - } - } - return array( - 'extensions' => $extensions, - 'zend_extensions' => $zend_extensions, - 'extension_dir' => $extension_dir, - 'all' => $all, - ); - } - - // {{{ doInstall() - - function doInstall($command, $options, $params) - { - if (!class_exists('PEAR_PackageFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php'; - } - - if (isset($options['installroot']) && isset($options['packagingroot'])) { - return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); - } - - $reg = &$this->config->getRegistry(); - $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - if (empty($this->installer)) { - $this->installer = &$this->getInstaller($this->ui); - } - - if ($command == 'upgrade' || $command == 'upgrade-all') { - // If people run the upgrade command but pass nothing, emulate a upgrade-all - if ($command == 'upgrade' && empty($params)) { - return $this->doUpgradeAll($command, $options, $params); - } - $options['upgrade'] = true; - } else { - $packages = $params; - } - - $instreg = &$reg; // instreg used to check if package is installed - if (isset($options['packagingroot']) && !isset($options['upgrade'])) { - $packrootphp_dir = $this->installer->_prependPath( - $this->config->get('php_dir', null, 'pear.php.net'), - $options['packagingroot']); - $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! - - if ($this->config->get('verbose') > 2) { - $this->ui->outputData('using package root: ' . $options['packagingroot']); - } - } - - $abstractpackages = $otherpackages = array(); - // parse params - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - - foreach ($params as $param) { - if (strpos($param, 'http://') === 0) { - $otherpackages[] = $param; - continue; - } - - if (strpos($param, 'channel://') === false && @file_exists($param)) { - if (isset($options['force'])) { - $otherpackages[] = $param; - continue; - } - - $pkg = new PEAR_PackageFile($this->config); - $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); - if (PEAR::isError($pf)) { - $otherpackages[] = $param; - continue; - } - - $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel()); - $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()); - $version_compare = version_compare($pf->getVersion(), $pversion, '<='); - if ($exists && $version_compare) { - if ($this->config->get('verbose')) { - $this->ui->outputData('Ignoring installed package ' . - $reg->parsedPackageNameToString( - array('package' => $pf->getPackage(), - 'channel' => $pf->getChannel()), true)); - } - continue; - } - $otherpackages[] = $param; - continue; - } - - $e = $reg->parsePackageName($param, $channel); - if (PEAR::isError($e)) { - $otherpackages[] = $param; - } else { - $abstractpackages[] = $e; - } - } - PEAR::staticPopErrorHandling(); - - // if there are any local package .tgz or remote static url, we can't - // filter. The filter only works for abstract packages - if (count($abstractpackages) && !isset($options['force'])) { - // when not being forced, only do necessary upgrades/installs - if (isset($options['upgrade'])) { - $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command); - } else { - $count = count($abstractpackages); - foreach ($abstractpackages as $i => $package) { - if (isset($package['group'])) { - // do not filter out install groups - continue; - } - - if ($instreg->packageExists($package['package'], $package['channel'])) { - if ($count > 1) { - if ($this->config->get('verbose')) { - $this->ui->outputData('Ignoring installed package ' . - $reg->parsedPackageNameToString($package, true)); - } - unset($abstractpackages[$i]); - } elseif ($count === 1) { - // Lets try to upgrade it since it's already installed - $options['upgrade'] = true; - } - } - } - } - $abstractpackages = - array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); - } elseif (count($abstractpackages)) { - $abstractpackages = - array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); - } - - $packages = array_merge($abstractpackages, $otherpackages); - if (!count($packages)) { - $c = ''; - if (isset($options['channel'])){ - $c .= ' in channel "' . $options['channel'] . '"'; - } - $this->ui->outputData('Nothing to ' . $command . $c); - return true; - } - - $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); - $errors = $downloaded = $binaries = array(); - $downloaded = &$this->downloader->download($packages); - if (PEAR::isError($downloaded)) { - return $this->raiseError($downloaded); - } - - $errors = $this->downloader->getErrorMsgs(); - if (count($errors)) { - $err = array(); - $err['data'] = array(); - foreach ($errors as $error) { - if ($error !== null) { - $err['data'][] = array($error); - } - } - - if (!empty($err['data'])) { - $err['headline'] = 'Install Errors'; - $this->ui->outputData($err); - } - - if (!count($downloaded)) { - return $this->raiseError("$command failed"); - } - } - - $data = array( - 'headline' => 'Packages that would be Installed' - ); - - if (isset($options['pretend'])) { - foreach ($downloaded as $package) { - $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); - } - $this->ui->outputData($data, 'pretend'); - return true; - } - - $this->installer->setOptions($options); - $this->installer->sortPackagesForInstall($downloaded); - if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { - $this->raiseError($err->getMessage()); - return true; - } - - $binaries = $extrainfo = array(); - foreach ($downloaded as $param) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->install($param, $options); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - $oldinfo = $info; - $pkg = &$param->getPackageFile(); - if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { - if (!($info = $pkg->installBinary($this->installer))) { - $this->ui->outputData('ERROR: ' .$oldinfo->getMessage()); - continue; - } - - // we just installed a different package than requested, - // let's change the param and info so that the rest of this works - $param = $info[0]; - $info = $info[1]; - } - } - - if (!is_array($info)) { - return $this->raiseError("$command failed"); - } - - if ($param->getPackageType() == 'extsrc' || - $param->getPackageType() == 'extbin' || - $param->getPackageType() == 'zendextsrc' || - $param->getPackageType() == 'zendextbin') { - $pkg = &$param->getPackageFile(); - if ($instbin = $pkg->getInstalledBinary()) { - $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); - } else { - $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); - } - - foreach ($instpkg->getFilelist() as $name => $atts) { - $pinfo = pathinfo($atts['installed_as']); - if (!isset($pinfo['extension']) || - in_array($pinfo['extension'], array('c', 'h'))) { - continue; // make sure we don't match php_blah.h - } - - if ((strpos($pinfo['basename'], 'php_') === 0 && - $pinfo['extension'] == 'dll') || - // most unices - $pinfo['extension'] == 'so' || - // hp-ux - $pinfo['extension'] == 'sl') { - $binaries[] = array($atts['installed_as'], $pinfo); - break; - } - } - - if (count($binaries)) { - foreach ($binaries as $pinfo) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($ret)) { - $extrainfo[] = $ret->getMessage(); - if ($param->getPackageType() == 'extsrc' || - $param->getPackageType() == 'extbin') { - $exttype = 'extension'; - } else { - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $exttype = 'zend_extension' . $debug . $ts; - } - $extrainfo[] = 'You should add "' . $exttype . '=' . - $pinfo[1]['basename'] . '" to php.ini'; - } else { - $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . - ' enabled in php.ini'; - } - } - } - } - - if ($this->config->get('verbose') > 0) { - $chan = $param->getChannel(); - $label = $reg->parsedPackageNameToString( - array( - 'channel' => $chan, - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - )); - $out = array('data' => "$command ok: $label"); - if (isset($info['release_warnings'])) { - $out['release_warnings'] = $info['release_warnings']; - } - $this->ui->outputData($out, $command); - - if (!isset($options['register-only']) && !isset($options['offline'])) { - if ($this->config->isDefinedLayer('ftp')) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->ftpInstall($param); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - $this->ui->outputData($info->getMessage()); - $this->ui->outputData("remote install failed: $label"); - } else { - $this->ui->outputData("remote install ok: $label"); - } - } - } - } - - $deps = $param->getDeps(); - if ($deps) { - if (isset($deps['group'])) { - $groups = $deps['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } - - foreach ($groups as $group) { - if ($group['attribs']['name'] == 'default') { - // default group is always installed, unless the user - // explicitly chooses to install another group - continue; - } - $extrainfo[] = $param->getPackage() . ': Optional feature ' . - $group['attribs']['name'] . ' available (' . - $group['attribs']['hint'] . ')'; - } - - $extrainfo[] = $param->getPackage() . - ': To install optional features use "pear install ' . - $reg->parsedPackageNameToString( - array('package' => $param->getPackage(), - 'channel' => $param->getChannel()), true) . - '#featurename"'; - } - } - - $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel()); - // $pkg may be NULL if install is a 'fake' install via --packagingroot - if (is_object($pkg)) { - $pkg->setConfig($this->config); - if ($list = $pkg->listPostinstallScripts()) { - $pn = $reg->parsedPackageNameToString(array('channel' => - $param->getChannel(), 'package' => $param->getPackage()), true); - $extrainfo[] = $pn . ' has post-install scripts:'; - foreach ($list as $file) { - $extrainfo[] = $file; - } - $extrainfo[] = $param->getPackage() . - ': Use "pear run-scripts ' . $pn . '" to finish setup.'; - $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; - } - } - } - - if (count($extrainfo)) { - foreach ($extrainfo as $info) { - $this->ui->outputData($info); - } - } - - return true; - } - - // }}} - // {{{ doUpgradeAll() - - function doUpgradeAll($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - $upgrade = array(); - - if (isset($options['channel'])) { - $channels = array($options['channel']); - } else { - $channels = $reg->listChannels(); - } - - foreach ($channels as $channel) { - if ($channel == '__uri') { - continue; - } - - // parse name with channel - foreach ($reg->listPackages($channel) as $name) { - $upgrade[] = $reg->parsedPackageNameToString(array( - 'channel' => $channel, - 'package' => $name - )); - } - } - - $err = $this->doInstall($command, $options, $upgrade); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - } - } - - // }}} - // {{{ doUninstall() - - function doUninstall($command, $options, $params) - { - if (count($params) < 1) { - return $this->raiseError("Please supply the package(s) you want to uninstall"); - } - - if (empty($this->installer)) { - $this->installer = &$this->getInstaller($this->ui); - } - - if (isset($options['remoteconfig'])) { - $e = $this->config->readFTPConfigFile($options['remoteconfig']); - if (!PEAR::isError($e)) { - $this->installer->setConfig($this->config); - } - } - - $reg = &$this->config->getRegistry(); - $newparams = array(); - $binaries = array(); - $badparams = array(); - foreach ($params as $pkg) { - $channel = $this->config->get('default_channel'); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($pkg, $channel); - PEAR::staticPopErrorHandling(); - if (!$parsed || PEAR::isError($parsed)) { - $badparams[] = $pkg; - continue; - } - $package = $parsed['package']; - $channel = $parsed['channel']; - $info = &$reg->getPackage($package, $channel); - if ($info === null && - ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) { - // make sure this isn't a package that has flipped from pear to pecl but - // used a package.xml 1.0 - $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net'; - $info = &$reg->getPackage($package, $testc); - if ($info !== null) { - $channel = $testc; - } - } - if ($info === null) { - $badparams[] = $pkg; - } else { - $newparams[] = &$info; - // check for binary packages (this is an alias for those packages if so) - if ($installedbinary = $info->getInstalledBinary()) { - $this->ui->log('adding binary package ' . - $reg->parsedPackageNameToString(array('channel' => $channel, - 'package' => $installedbinary), true)); - $newparams[] = &$reg->getPackage($installedbinary, $channel); - } - // add the contents of a dependency group to the list of installed packages - if (isset($parsed['group'])) { - $group = $info->getDependencyGroup($parsed['group']); - if ($group) { - $installed = $reg->getInstalledGroup($group); - if ($installed) { - foreach ($installed as $i => $p) { - $newparams[] = &$installed[$i]; - } - } - } - } - } - } - $err = $this->installer->sortPackagesForUninstall($newparams); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - return true; - } - $params = $newparams; - // twist this to use it to check on whether dependent packages are also being uninstalled - // for circular dependencies like subpackages - $this->installer->setUninstallPackages($newparams); - $params = array_merge($params, $badparams); - $binaries = array(); - foreach ($params as $pkg) { - $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); - if ($err = $this->installer->uninstall($pkg, $options)) { - $this->installer->popErrorHandling(); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - continue; - } - if ($pkg->getPackageType() == 'extsrc' || - $pkg->getPackageType() == 'extbin' || - $pkg->getPackageType() == 'zendextsrc' || - $pkg->getPackageType() == 'zendextbin') { - if ($instbin = $pkg->getInstalledBinary()) { - continue; // this will be uninstalled later - } - - foreach ($pkg->getFilelist() as $name => $atts) { - $pinfo = pathinfo($atts['installed_as']); - if (!isset($pinfo['extension']) || - in_array($pinfo['extension'], array('c', 'h'))) { - continue; // make sure we don't match php_blah.h - } - if ((strpos($pinfo['basename'], 'php_') === 0 && - $pinfo['extension'] == 'dll') || - // most unices - $pinfo['extension'] == 'so' || - // hp-ux - $pinfo['extension'] == 'sl') { - $binaries[] = array($atts['installed_as'], $pinfo); - break; - } - } - if (count($binaries)) { - foreach ($binaries as $pinfo) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($ret)) { - $extrainfo[] = $ret->getMessage(); - if ($pkg->getPackageType() == 'extsrc' || - $pkg->getPackageType() == 'extbin') { - $exttype = 'extension'; - } else { - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $exttype = 'zend_extension' . $debug . $ts; - } - $this->ui->outputData('Unable to remove "' . $exttype . '=' . - $pinfo[1]['basename'] . '" from php.ini', $command); - } else { - $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() . - ' disabled in php.ini', $command); - } - } - } - } - $savepkg = $pkg; - if ($this->config->get('verbose') > 0) { - if (is_object($pkg)) { - $pkg = $reg->parsedPackageNameToString($pkg); - } - $this->ui->outputData("uninstall ok: $pkg", $command); - } - if (!isset($options['offline']) && is_object($savepkg) && - defined('PEAR_REMOTEINSTALL_OK')) { - if ($this->config->isDefinedLayer('ftp')) { - $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->ftpUninstall($savepkg); - $this->installer->popErrorHandling(); - if (PEAR::isError($info)) { - $this->ui->outputData($info->getMessage()); - $this->ui->outputData("remote uninstall failed: $pkg"); - } else { - $this->ui->outputData("remote uninstall ok: $pkg"); - } - } - } - } else { - $this->installer->popErrorHandling(); - if (!is_object($pkg)) { - return $this->raiseError("uninstall failed: $pkg"); - } - $pkg = $reg->parsedPackageNameToString($pkg); - } - } - - return true; - } - - // }}} - - - // }}} - // {{{ doBundle() - /* - (cox) It just downloads and untars the package, does not do - any check that the PEAR_Installer::_installFile() does. - */ - - function doBundle($command, $options, $params) - { - $opts = array( - 'force' => true, - 'nodeps' => true, - 'soft' => true, - 'downloadonly' => true - ); - $downloader = &$this->getDownloader($this->ui, $opts, $this->config); - $reg = &$this->config->getRegistry(); - if (count($params) < 1) { - return $this->raiseError("Please supply the package you want to bundle"); - } - - if (isset($options['destination'])) { - if (!is_dir($options['destination'])) { - System::mkdir('-p ' . $options['destination']); - } - $dest = realpath($options['destination']); - } else { - $pwd = getcwd(); - $dir = $pwd . DIRECTORY_SEPARATOR . 'ext'; - $dest = is_dir($dir) ? $dir : $pwd; - } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $downloader->setDownloadDir($dest); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($err)) { - return PEAR::raiseError('download directory "' . $dest . - '" is not writeable.'); - } - $result = &$downloader->download(array($params[0])); - if (PEAR::isError($result)) { - return $result; - } - if (!isset($result[0])) { - return $this->raiseError('unable to unpack ' . $params[0]); - } - $pkgfile = &$result[0]->getPackageFile(); - $pkgname = $pkgfile->getName(); - $pkgversion = $pkgfile->getVersion(); - - // Unpacking ------------------------------------------------- - $dest .= DIRECTORY_SEPARATOR . $pkgname; - $orig = $pkgname . '-' . $pkgversion; - - $tar = &new Archive_Tar($pkgfile->getArchiveFile()); - if (!$tar->extractModify($dest, $orig)) { - return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile()); - } - $this->ui->outputData("Package ready at '$dest'"); - // }}} - } - - // }}} - - function doRunScripts($command, $options, $params) - { - if (!isset($params[0])) { - return $this->raiseError('run-scripts expects 1 parameter: a package name'); - } - - $reg = &$this->config->getRegistry(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($parsed)) { - return $this->raiseError($parsed); - } - - $package = &$reg->getPackage($parsed['package'], $parsed['channel']); - if (!is_object($package)) { - return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry'); - } - - $package->setConfig($this->config); - $package->runPostinstallScripts(); - $this->ui->outputData('Install scripts complete', $command); - return true; - } - - /** - * Given a list of packages, filter out those ones that are already up to date - * - * @param $packages: packages, in parsed array format ! - * @return list of packages that can be upgraded - */ - function _filterUptodatePackages($packages, $command) - { - $reg = &$this->config->getRegistry(); - $latestReleases = array(); - - $ret = array(); - foreach ($packages as $package) { - if (isset($package['group'])) { - $ret[] = $package; - continue; - } - - $channel = $package['channel']; - $name = $package['package']; - if (!$reg->packageExists($name, $channel)) { - $ret[] = $package; - continue; - } - - if (!isset($latestReleases[$channel])) { - // fill in cache for this channel - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); - } - - $base2 = false; - $preferred_mirror = $this->config->get('preferred_mirror', null, $channel); - if ($chan->supportsREST($preferred_mirror) && - ( - //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || - ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - ) { - $dorest = true; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!isset($package['state'])) { - $state = $this->config->get('preferred_state', null, $channel); - } else { - $state = $package['state']; - } - - if ($dorest) { - if ($base2) { - $rest = &$this->config->getREST('1.4', array()); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', array()); - } - - $installed = array_flip($reg->listPackages($channel)); - $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); - } - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($latest)) { - $this->ui->outputData('Error getting channel info from ' . $channel . - ': ' . $latest->getMessage()); - continue; - } - - $latestReleases[$channel] = array_change_key_case($latest); - } - - // check package for latest release - $name_lower = strtolower($name); - if (isset($latestReleases[$channel][$name_lower])) { - // if not set, up to date - $inst_version = $reg->packageInfo($name, 'version', $channel); - $channel_version = $latestReleases[$channel][$name_lower]['version']; - if (version_compare($channel_version, $inst_version, 'le')) { - // installed version is up-to-date - continue; - } - - // maintain BC - if ($command == 'upgrade-all') { - $this->ui->outputData(array('data' => 'Will upgrade ' . - $reg->parsedPackageNameToString($package)), $command); - } - $ret[] = $package; - } - } - - return $ret; - } -} - - Install Package - doInstall - i - - - f - will overwrite newer installed packages - - - l - do not check for recommended dependency version - - - n - ignore dependencies, install anyway - - - r - do not install files, only register the package as installed - - - s - soft install, fail silently, or upgrade if already installed - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM - DIR - - - P - root directory used when packaging files, like RPM packaging - DIR - - - - force install even if there were errors - - - a - install all required and optional dependencies - - - o - install all required dependencies - - - O - do not attempt to download any urls or contact channels - - - p - Only list the packages that would be downloaded - - - [channel/]<package> ... -Installs one or more PEAR packages. You can specify a package to -install in four ways: - -"Package-1.0.tgz" : installs from a local file - -"http://example.com/Package-1.0.tgz" : installs from -anywhere on the net. - -"package.xml" : installs the package described in -package.xml. Useful for testing, or for wrapping a PEAR package in -another package manager such as RPM. - -"Package[-version/state][.tar]" : queries your default channel's server -({config master_server}) and downloads the newest package with -the preferred quality/state ({config preferred_state}). - -To retrieve Package version 1.1, use "Package-1.1," to retrieve -Package state beta, use "Package-beta." To retrieve an uncompressed -file, append .tar (make sure there is no file by the same name first) - -To download a package from another channel, prefix with the channel name like -"channel/Package" - -More than one package may be specified at once. It is ok to mix these -four ways of specifying packages. - - - - Upgrade Package - doInstall - up - - - c - upgrade packages from a specific channel - CHAN - - - f - overwrite newer installed packages - - - l - do not check for recommended dependency version - - - n - ignore dependencies, upgrade anyway - - - r - do not install files, only register the package as upgraded - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT) - DIR - - - - force install even if there were errors - - - a - install all required and optional dependencies - - - o - install all required dependencies - - - O - do not attempt to download any urls or contact channels - - - p - Only list the packages that would be downloaded - - - <package> ... -Upgrades one or more PEAR packages. See documentation for the -"install" command for ways to specify a package. - -When upgrading, your package will be updated if the provided new -package has a higher version number (use the -f option if you need to -upgrade anyway). - -More than one package may be specified at once. - - - - Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters] - doUpgradeAll - ua - - - c - upgrade packages from a specific channel - CHAN - - - n - ignore dependencies, upgrade anyway - - - r - do not install files, only register the package as upgraded - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM - DIR - - - - force install even if there were errors - - - - do not check for recommended dependency version - - - -WARNING: This function is deprecated in favor of using the upgrade command with no params - -Upgrades all packages that have a newer release available. Upgrades are -done only if there is a release available of the state specified in -"preferred_state" (currently {config preferred_state}), or a state considered -more stable. - - - - Un-install Package - doUninstall - un - - - n - ignore dependencies, uninstall anyway - - - r - do not remove files, only register the packages as not installed - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT) - DIR - - - - force install even if there were errors - - - O - do not attempt to uninstall remotely - - - [channel/]<package> ... -Uninstalls one or more PEAR packages. More than one package may be -specified at once. Prefix with channel name to uninstall from a -channel not in your default channel ({config default_channel}) - - - - Unpacks a Pecl Package - doBundle - bun - - - d - Optional destination directory for unpacking (defaults to current path or "ext" if exists) - DIR - - - f - Force the unpacking even if there were errors in the package - - - <package> -Unpacks a Pecl Package into the selected location. It will download the -package if needed. - - - - Run Post-Install Scripts bundled with a package - doRunScripts - rs - - <package> -Run post-installation scripts in package <package>, if any exist. - - - - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 282969 2009-06-28 23:09:27Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1.0 - * @deprecated File deprecated since Release 1.4.0a1 - */ - -/** - * Include error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; - -/** - * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() - */ -define('PEAR_COMMON_ERROR_INVALIDPHP', 1); -define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); -define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); - -// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 -define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); -define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); - -// XXX far from perfect :-) -define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . - ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . - '\\z/'); - -define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); -define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); - -// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED -define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); -define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); - -define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); -define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); - -define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); - -/** - * List of temporary files and directories registered by - * PEAR_Common::addTempFile(). - * @var array - */ -$GLOBALS['_PEAR_Common_tempfiles'] = array(); - -/** - * Valid maintainer roles - * @var array - */ -$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); - -/** - * Valid release states - * @var array - */ -$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); - -/** - * Valid dependency types - * @var array - */ -$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); - -/** - * Valid dependency relations - * @var array - */ -$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); - -/** - * Valid file roles - * @var array - */ -$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); - -/** - * Valid replacement types - * @var array - */ -$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); - -/** - * Valid "provide" types - * @var array - */ -$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); - -/** - * Valid "provide" types - * @var array - */ -$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); - -/** - * Class providing common functionality for PEAR administration classes. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - * @deprecated This class will disappear, and its components will be spread - * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 - */ -class PEAR_Common extends PEAR -{ - /** - * User Interface object (PEAR_Frontend_* class). If null, - * the log() method uses print. - * @var object - */ - var $ui = null; - - /** - * Configuration object (PEAR_Config). - * @var PEAR_Config - */ - var $config = null; - - /** stack of elements, gives some sort of XML context */ - var $element_stack = array(); - - /** name of currently parsed XML element */ - var $current_element; - - /** array of attributes of the currently parsed XML element */ - var $current_attributes = array(); - - /** assoc with information about a package */ - var $pkginfo = array(); - - var $current_path = null; - - /** - * Flag variable used to mark a valid package file - * @var boolean - * @access private - */ - var $_validPackageFile; - - /** - * PEAR_Common constructor - * - * @access public - */ - function PEAR_Common() - { - parent::PEAR(); - $this->config = &PEAR_Config::singleton(); - $this->debug = $this->config->get('verbose'); - } - - /** - * PEAR_Common destructor - * - * @access private - */ - function _PEAR_Common() - { - // doesn't work due to bug #14744 - //$tempfiles = $this->_tempfiles; - $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; - while ($file = array_shift($tempfiles)) { - if (@is_dir($file)) { - if (!class_exists('System')) { - require_once 'phar://go-pear.phar/' . 'System.php'; - } - - System::rm(array('-rf', $file)); - } elseif (file_exists($file)) { - unlink($file); - } - } - } - - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * - * @return void - * - * @access public - */ - function addTempFile($file) - { - if (!class_exists('PEAR_Frontend')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php'; - } - PEAR_Frontend::addTempFile($file); - } - - /** - * Wrapper to System::mkDir(), creates a directory as well as - * any necessary parent directories. - * - * @param string $dir directory name - * - * @return bool TRUE on success, or a PEAR error - * - * @access public - */ - function mkDirHier($dir) - { - // Only used in Installer - move it there ? - $this->log(2, "+ create dir $dir"); - if (!class_exists('System')) { - require_once 'phar://go-pear.phar/' . 'System.php'; - } - return System::mkDir(array('-p', $dir)); - } - - /** - * Logging method. - * - * @param int $level log level (0 is quiet, higher is noisier) - * @param string $msg message to write to the log - * - * @return void - * - * @access public - * @static - */ - function log($level, $msg, $append_crlf = true) - { - if ($this->debug >= $level) { - if (!class_exists('PEAR_Frontend')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php'; - } - - $ui = &PEAR_Frontend::singleton(); - if (is_a($ui, 'PEAR_Frontend')) { - $ui->log($msg, $append_crlf); - } else { - print "$msg\n"; - } - } - } - - /** - * Create and register a temporary directory. - * - * @param string $tmpdir (optional) Directory to use as tmpdir. - * Will use system defaults (for example - * /tmp or c:\windows\temp) if not specified - * - * @return string name of created directory - * - * @access public - */ - function mkTempDir($tmpdir = '') - { - $topt = $tmpdir ? array('-t', $tmpdir) : array(); - $topt = array_merge($topt, array('-d', 'pear')); - if (!class_exists('System')) { - require_once 'phar://go-pear.phar/' . 'System.php'; - } - - if (!$tmpdir = System::mktemp($topt)) { - return false; - } - - $this->addTempFile($tmpdir); - return $tmpdir; - } - - /** - * Set object that represents the frontend to be used. - * - * @param object Reference of the frontend object - * @return void - * @access public - */ - function setFrontendObject(&$ui) - { - $this->ui = &$ui; - } - - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - if ($include) { - $i--; - } - return array_slice($states, $i + 1); - } - - /** - * Get the valid roles for a PEAR package maintainer - * - * @return array - * @static - */ - function getUserRoles() - { - return $GLOBALS['_PEAR_Common_maintainer_roles']; - } - - /** - * Get the valid package release states of packages - * - * @return array - * @static - */ - function getReleaseStates() - { - return $GLOBALS['_PEAR_Common_release_states']; - } - - /** - * Get the implemented dependency types (php, ext, pkg etc.) - * - * @return array - * @static - */ - function getDependencyTypes() - { - return $GLOBALS['_PEAR_Common_dependency_types']; - } - - /** - * Get the implemented dependency relations (has, lt, ge etc.) - * - * @return array - * @static - */ - function getDependencyRelations() - { - return $GLOBALS['_PEAR_Common_dependency_relations']; - } - - /** - * Get the implemented file roles - * - * @return array - * @static - */ - function getFileRoles() - { - return $GLOBALS['_PEAR_Common_file_roles']; - } - - /** - * Get the implemented file replacement types in - * - * @return array - * @static - */ - function getReplacementTypes() - { - return $GLOBALS['_PEAR_Common_replacement_types']; - } - - /** - * Get the implemented file replacement types in - * - * @return array - * @static - */ - function getProvideTypes() - { - return $GLOBALS['_PEAR_Common_provide_types']; - } - - /** - * Get the implemented file replacement types in - * - * @return array - * @static - */ - function getScriptPhases() - { - return $GLOBALS['_PEAR_Common_script_phases']; - } - - /** - * Test whether a string contains a valid package name. - * - * @param string $name the package name to test - * - * @return bool - * - * @access public - */ - function validPackageName($name) - { - return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); - } - - /** - * Test whether a string contains a valid package version. - * - * @param string $ver the package version to test - * - * @return bool - * - * @access public - */ - function validPackageVersion($ver) - { - return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); - } - - /** - * @param string $path relative or absolute include path - * @return boolean - * @static - */ - function isIncludeable($path) - { - if (file_exists($path) && is_readable($path)) { - return true; - } - - $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($ipath as $include) { - $test = realpath($include . DIRECTORY_SEPARATOR . $path); - if (file_exists($test) && is_readable($test)) { - return true; - } - } - - return false; - } - - function _postProcessChecks($pf) - { - if (!PEAR::isError($pf)) { - return $this->_postProcessValidPackagexml($pf); - } - - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; - } - - /** - * Returns information about a package file. Expects the name of - * a gzipped tar file as input. - * - * @param string $file name of .tgz file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromTgzFile() instead - * - */ - function infoFromTgzFile($file) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); - return $this->_postProcessChecks($pf); - } - - /** - * Returns information about a package file. Expects the name of - * a package xml file as input. - * - * @param string $descfile name of package xml file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromPackageFile() instead - * - */ - function infoFromDescriptionFile($descfile) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - return $this->_postProcessChecks($pf); - } - - /** - * Returns information about a package file. Expects the contents - * of a package xml file as input. - * - * @param string $data contents of package.xml file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromXmlstring() instead - * - */ - function infoFromString($data) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); - return $this->_postProcessChecks($pf); - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return array - */ - function _postProcessValidPackagexml(&$pf) - { - if (!is_a($pf, 'PEAR_PackageFile_v2')) { - $this->pkginfo = $pf->toArray(); - return $this->pkginfo; - } - - // sort of make this into a package.xml 1.0-style array - // changelog is not converted to old format. - $arr = $pf->toArray(true); - $arr = array_merge($arr, $arr['old']); - unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'], - $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'], - $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'], - $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'], - $arr['helper'], $arr['contributor']); - $arr['filelist'] = $pf->getFilelist(); - $this->pkginfo = $arr; - return $arr; - } - - /** - * Returns package information from different sources - * - * This method is able to extract information about a package - * from a .tgz archive or from a XML package definition file. - * - * @access public - * @param string Filename of the source ('package.xml', '.tgz') - * @return string - * @deprecated use PEAR_PackageFile->fromAnyFile() instead - */ - function infoFromAny($info) - { - if (is_string($info) && file_exists($info)) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; - } - - return $this->_postProcessValidPackagexml($pf); - } - - return $info; - } - - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @param array $pkginfo package info - * - * @return string XML data - * - * @access public - * @deprecated use a PEAR_PackageFile_v* object's generator instead - */ - function xmlFromInfo($pkginfo) - { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - $pf = &$packagefile->fromArray($pkginfo); - $gen = &$pf->getDefaultGenerator(); - return $gen->toXml(PEAR_VALIDATE_PACKAGING); - } - - /** - * Validate XML package definition file. - * - * @param string $info Filename of the package archive or of the - * package definition file - * @param array $errors Array that will contain the errors - * @param array $warnings Array that will contain the warnings - * @param string $dir_prefix (optional) directory where source files - * may be found, or empty if they are not available - * @access public - * @return boolean - * @deprecated use the validation of PEAR_PackageFile objects - */ - function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') - { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); - } else { - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); - } - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - if ($error['level'] == 'error') { - $errors[] = $error['message']; - } else { - $warnings[] = $error['message']; - } - } - } - - return false; - } - - return true; - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access public - * - */ - function buildProvidesArray($srcinfo) - { - $file = basename($srcinfo['source_file']); - $pn = ''; - if (isset($this->_packageName)) { - $pn = $this->_packageName; - } - - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->pkginfo['provides'][$key])) { - continue; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->pkginfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->pkginfo['provides'][$key])) { - continue; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { - continue; - } - - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access public - */ - function analyzeSourceCode($file) - { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/Validator.php'; - } - - $a = new PEAR_PackageFile_v2_Validator; - return $a->analyzeSourceCode($file); - } - - function detectDependencies($any, $status_callback = null) - { - if (!function_exists("token_get_all")) { - return false; - } - - if (PEAR::isError($info = $this->infoFromAny($any))) { - return $this->raiseError($info); - } - - if (!is_array($info)) { - return false; - } - - $deps = array(); - $used_c = $decl_c = $decl_f = $decl_m = array(); - foreach ($info['filelist'] as $file => $fa) { - $tmp = $this->analyzeSourceCode($file); - $used_c = @array_merge($used_c, $tmp['used_classes']); - $decl_c = @array_merge($decl_c, $tmp['declared_classes']); - $decl_f = @array_merge($decl_f, $tmp['declared_functions']); - $decl_m = @array_merge($decl_m, $tmp['declared_methods']); - $inheri = @array_merge($inheri, $tmp['inheritance']); - } - - $used_c = array_unique($used_c); - $decl_c = array_unique($decl_c); - $undecl_c = array_diff($used_c, $decl_c); - - return array('used_classes' => $used_c, - 'declared_classes' => $decl_c, - 'declared_methods' => $decl_m, - 'declared_functions' => $decl_f, - 'undeclared_classes' => $undecl_c, - 'inheritance' => $inheri, - ); - } - - /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir (optional) directory to save file in - * @param mixed $callback (optional) function/method to call for status - * updates - * - * @return string Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). - * - * @access public - * @deprecated in favor of PEAR_Downloader::downloadHttp() - */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) - { - if (!class_exists('PEAR_Downloader')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php'; - } - return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); - } -} - -require_once 'phar://go-pear.phar/' . 'PEAR/Config.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php'; - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Config.php 286480 2009-07-29 02:50:02Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Required for error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Registry.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php'; -require_once 'phar://go-pear.phar/' . 'System.php'; - -/** - * Last created PEAR_Config instance. - * @var object - */ -$GLOBALS['_PEAR_Config_instance'] = null; -if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { - $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; -} else { - $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; -} - -// Below we define constants with default values for all configuration -// parameters except username/password. All of them can have their -// defaults set through environment variables. The reason we use the -// PHP_ prefix is for some security, PHP protects environment -// variables starting with PHP_*. - -// default channel and preferred mirror is based on whether we are invoked through -// the "pear" or the "pecl" command -if (!defined('PEAR_RUNTYPE')) { - define('PEAR_RUNTYPE', 'pear'); -} - -if (PEAR_RUNTYPE == 'pear') { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); -} else { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); -} - -if (getenv('PHP_PEAR_SYSCONF_DIR')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); -} elseif (getenv('SystemRoot')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); -} else { - define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); -} - -// Default for master_server -if (getenv('PHP_PEAR_MASTER_SERVER')) { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); -} else { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); -} - -// Default for http_proxy -if (getenv('PHP_PEAR_HTTP_PROXY')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); -} elseif (getenv('http_proxy')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); -} else { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); -} - -// Default for php_dir -if (getenv('PHP_PEAR_INSTALL_DIR')) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); -} else { - if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } -} - -// Default for ext_dir -if (getenv('PHP_PEAR_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); -} else { - if (ini_get('extension_dir')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); - } elseif (defined('PEAR_EXTENSION_DIR') && - file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); - } elseif (defined('PHP_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); - } -} - -// Default for doc_dir -if (getenv('PHP_PEAR_DOC_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); -} - -// Default for bin_dir -if (getenv('PHP_PEAR_BIN_DIR')) { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); -} - -// Default for data_dir -if (getenv('PHP_PEAR_DATA_DIR')) { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); -} - -// Default for cfg_dir -if (getenv('PHP_PEAR_CFG_DIR')) { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); -} - -// Default for www_dir -if (getenv('PHP_PEAR_WWW_DIR')) { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); -} - -// Default for test_dir -if (getenv('PHP_PEAR_TEST_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); -} - -// Default for temp_dir -if (getenv('PHP_PEAR_TEMP_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'temp'); -} - -// Default for cache_dir -if (getenv('PHP_PEAR_CACHE_DIR')) { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'cache'); -} - -// Default for download_dir -if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'download'); -} - -// Default for php_bin -if (getenv('PHP_PEAR_PHP_BIN')) { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. - DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); -} - -// Default for verbose -if (getenv('PHP_PEAR_VERBOSE')) { - define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); -} else { - define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); -} - -// Default for preferred_state -if (getenv('PHP_PEAR_PREFERRED_STATE')) { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); -} else { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); -} - -// Default for umask -if (getenv('PHP_PEAR_UMASK')) { - define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); -} else { - define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); -} - -// Default for cache_ttl -if (getenv('PHP_PEAR_CACHE_TTL')) { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); -} - -// Default for sig_type -if (getenv('PHP_PEAR_SIG_TYPE')) { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); -} - -// Default for sig_bin -if (getenv('PHP_PEAR_SIG_BIN')) { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', - System::which( - 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); -} - -// Default for sig_keydir -if (getenv('PHP_PEAR_SIG_KEYDIR')) { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', - PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); -} - -/** - * This is a class for storing configuration data, keeping track of - * which are system-defined, user-defined or defaulted. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Config extends PEAR -{ - /** - * Array of config files used. - * - * @var array layer => config file - */ - var $files = array( - 'system' => '', - 'user' => '', - ); - - var $layers = array(); - - /** - * Configuration data, two-dimensional array where the first - * dimension is the config layer ('user', 'system' and 'default'), - * and the second dimension is keyname => value. - * - * The order in the first dimension is important! Earlier - * layers will shadow later ones when a config value is - * requested (if a 'user' value exists, it will be returned first, - * then 'system' and finally 'default'). - * - * @var array layer => array(keyname => value, ...) - */ - var $configuration = array( - 'user' => array(), - 'system' => array(), - 'default' => array(), - ); - - /** - * Configuration values that can be set for a channel - * - * All other configuration values can only have a global value - * @var array - * @access private - */ - var $_channelConfigInfo = array( - 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', - 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', - 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' - ); - - /** - * Channels that can be accessed - * @see setChannels() - * @var array - * @access private - */ - var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); - - /** - * This variable is used to control the directory values returned - * @see setInstallRoot(); - * @var string|false - * @access private - */ - var $_installRoot = false; - - /** - * If requested, this will always refer to the registry - * contained in php_dir - * @var PEAR_Registry - */ - var $_registry = array(); - - /** - * @var array - * @access private - */ - var $_regInitialized = array(); - - /** - * @var bool - * @access private - */ - var $_noRegistry = false; - - /** - * amount of errors found while parsing config - * @var integer - * @access private - */ - var $_errorsFound = 0; - var $_lastError = null; - - /** - * Information about the configuration data. Stores the type, - * default value and a documentation string for each configuration - * value. - * - * @var array layer => array(infotype => value, ...) - */ - var $configuration_info = array( - // Channels/Internet Access - 'default_channel' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default channel to use for all non explicit commands', - 'prompt' => 'Default Channel', - 'group' => 'Internet Access', - ), - 'preferred_mirror' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default server or mirror to use for channel actions', - 'prompt' => 'Default Channel Mirror', - 'group' => 'Internet Access', - ), - 'remote_config' => array( - 'type' => 'password', - 'default' => '', - 'doc' => 'ftp url of remote configuration file to use for synchronized install', - 'prompt' => 'Remote Configuration File', - 'group' => 'Internet Access', - ), - 'auto_discover' => array( - 'type' => 'integer', - 'default' => 0, - 'doc' => 'whether to automatically discover new channels', - 'prompt' => 'Auto-discover new Channels', - 'group' => 'Internet Access', - ), - // Internet Access - 'master_server' => array( - 'type' => 'string', - 'default' => 'pear.php.net', - 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', - 'prompt' => 'PEAR server [DEPRECATED]', - 'group' => 'Internet Access', - ), - 'http_proxy' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, - 'doc' => 'HTTP proxy (host:port) to use when downloading packages', - 'prompt' => 'HTTP Proxy Server Address', - 'group' => 'Internet Access', - ), - // File Locations - 'php_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, - 'doc' => 'directory where .php files are installed', - 'prompt' => 'PEAR directory', - 'group' => 'File Locations', - ), - 'ext_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, - 'doc' => 'directory where loadable extensions are installed', - 'prompt' => 'PHP extension directory', - 'group' => 'File Locations', - ), - 'doc_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, - 'doc' => 'directory where documentation is installed', - 'prompt' => 'PEAR documentation directory', - 'group' => 'File Locations', - ), - 'bin_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, - 'doc' => 'directory where executables are installed', - 'prompt' => 'PEAR executables directory', - 'group' => 'File Locations', - ), - 'data_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, - 'doc' => 'directory where data files are installed', - 'prompt' => 'PEAR data directory', - 'group' => 'File Locations (Advanced)', - ), - 'cfg_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, - 'doc' => 'directory where modifiable configuration files are installed', - 'prompt' => 'PEAR configuration file directory', - 'group' => 'File Locations (Advanced)', - ), - 'www_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, - 'doc' => 'directory where www frontend files (html/js) are installed', - 'prompt' => 'PEAR www files directory', - 'group' => 'File Locations (Advanced)', - ), - 'test_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, - 'doc' => 'directory where regression tests are installed', - 'prompt' => 'PEAR test directory', - 'group' => 'File Locations (Advanced)', - ), - 'cache_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, - 'doc' => 'directory which is used for web service cache', - 'prompt' => 'PEAR Installer cache directory', - 'group' => 'File Locations (Advanced)', - ), - 'temp_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, - 'doc' => 'directory which is used for all temp files', - 'prompt' => 'PEAR Installer temp directory', - 'group' => 'File Locations (Advanced)', - ), - 'download_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, - 'doc' => 'directory which is used for all downloaded files', - 'prompt' => 'PEAR Installer download directory', - 'group' => 'File Locations (Advanced)', - ), - 'php_bin' => array( - 'type' => 'file', - 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, - 'doc' => 'PHP CLI/CGI binary for executing scripts', - 'prompt' => 'PHP CLI/CGI binary', - 'group' => 'File Locations (Advanced)', - ), - 'php_prefix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-prefix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_suffix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-suffix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_ini' => array( - 'type' => 'file', - 'default' => '', - 'doc' => 'location of php.ini in which to enable PECL extensions on install', - 'prompt' => 'php.ini location', - 'group' => 'File Locations (Advanced)', - ), - // Maintainers - 'username' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '(maintainers) your PEAR account name', - 'prompt' => 'PEAR username (for maintainers)', - 'group' => 'Maintainers', - ), - 'password' => array( - 'type' => 'password', - 'default' => '', - 'doc' => '(maintainers) your PEAR account password', - 'prompt' => 'PEAR password (for maintainers)', - 'group' => 'Maintainers', - ), - // Advanced - 'verbose' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, - 'doc' => 'verbosity level -0: really quiet -1: somewhat quiet -2: verbose -3: debug', - 'prompt' => 'Debug Log Level', - 'group' => 'Advanced', - ), - 'preferred_state' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, - 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', - 'valid_set' => array( - 'stable', 'beta', 'alpha', 'devel', 'snapshot'), - 'prompt' => 'Preferred Package State', - 'group' => 'Advanced', - ), - 'umask' => array( - 'type' => 'mask', - 'default' => PEAR_CONFIG_DEFAULT_UMASK, - 'doc' => 'umask used when creating files (Unix-like systems only)', - 'prompt' => 'Unix file mask', - 'group' => 'Advanced', - ), - 'cache_ttl' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, - 'doc' => 'amount of secs where the local cache is used and not updated', - 'prompt' => 'Cache TimeToLive', - 'group' => 'Advanced', - ), - 'sig_type' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, - 'doc' => 'which package signature mechanism to use', - 'valid_set' => array('gpg'), - 'prompt' => 'Package Signature Type', - 'group' => 'Maintainers', - ), - 'sig_bin' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, - 'doc' => 'which package signature mechanism to use', - 'prompt' => 'Signature Handling Program', - 'group' => 'Maintainers', - ), - 'sig_keyid' => array( - 'type' => 'string', - 'default' => '', - 'doc' => 'which key to use for signing with', - 'prompt' => 'Signature Key Id', - 'group' => 'Maintainers', - ), - 'sig_keydir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, - 'doc' => 'directory where signature keys are located', - 'prompt' => 'Signature Key Directory', - 'group' => 'Maintainers', - ), - // __channels is reserved - used for channel-specific configuration - ); - - /** - * Constructor. - * - * @param string file to read user-defined options from - * @param string file to read system-wide defaults from - * @param bool determines whether a registry object "follows" - * the value of php_dir (is automatically created - * and moved when php_dir is changed) - * @param bool if true, fails if configuration files cannot be loaded - * - * @access public - * - * @see PEAR_Config::singleton - */ - function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, - $strict = true) - { - $this->PEAR(); - PEAR_Installer_Role::initializeConfig($this); - $sl = DIRECTORY_SEPARATOR; - if (empty($user_file)) { - if (OS_WINDOWS) { - $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; - } else { - $user_file = getenv('HOME') . $sl . '.pearrc'; - } - } - - if (empty($system_file)) { - $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; - if (OS_WINDOWS) { - $system_file .= 'pearsys.ini'; - } else { - $system_file .= 'pear.conf'; - } - } - - $this->layers = array_keys($this->configuration); - $this->files['user'] = $user_file; - $this->files['system'] = $system_file; - if ($user_file && file_exists($user_file)) { - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->readConfigFile($user_file, 'user', $strict); - $this->popErrorHandling(); - if ($this->_errorsFound > 0) { - return; - } - } - - if ($system_file && @file_exists($system_file)) { - $this->mergeConfigFile($system_file, false, 'system', $strict); - if ($this->_errorsFound > 0) { - return; - } - - } - - if (!$ftp_file) { - $ftp_file = $this->get('remote_config'); - } - - if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { - $this->readFTPConfigFile($ftp_file); - } - - foreach ($this->configuration_info as $key => $info) { - $this->configuration['default'][$key] = $info['default']; - } - - $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); - $this->_registry['default']->setConfig($this, false); - $this->_regInitialized['default'] = false; - //$GLOBALS['_PEAR_Config_instance'] = &$this; - } - - /** - * Return the default locations of user and system configuration files - * @static - */ - function getDefaultConfigFiles() - { - $sl = DIRECTORY_SEPARATOR; - if (OS_WINDOWS) { - return array( - 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' - ); - } - - return array( - 'user' => getenv('HOME') . $sl . '.pearrc', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' - ); - } - - /** - * Static singleton method. If you want to keep only one instance - * of this class in use, this method will give you a reference to - * the last created PEAR_Config object if one exists, or create a - * new object. - * - * @param string (optional) file to read user-defined options from - * @param string (optional) file to read system-wide defaults from - * - * @return object an existing or new PEAR_Config instance - * - * @access public - * - * @see PEAR_Config::PEAR_Config - */ - function &singleton($user_file = '', $system_file = '', $strict = true) - { - if (is_object($GLOBALS['_PEAR_Config_instance'])) { - return $GLOBALS['_PEAR_Config_instance']; - } - - $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); - if ($t_conf->_errorsFound > 0) { - return $t_conf->lastError; - } - - $GLOBALS['_PEAR_Config_instance'] = &$t_conf; - return $GLOBALS['_PEAR_Config_instance']; - } - - /** - * Determine whether any configuration files have been detected, and whether a - * registry object can be retrieved from this configuration. - * @return bool - * @since PEAR 1.4.0a1 - */ - function validConfiguration() - { - if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { - return true; - } - - return false; - } - - /** - * Reads configuration data from a file. All existing values in - * the config layer are discarded and replaced with data from the - * file. - * @param string file to read from, if NULL or not specified, the - * last-used file for the same layer (second param) is used - * @param string config layer to insert data into ('user' or 'system') - * @return bool TRUE on success or a PEAR error on failure - */ - function readConfigFile($file = null, $layer = 'user', $strict = true) - { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; - } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; - } - - $this->files[$layer] = $file; - $this->_decodeInput($data); - $this->configuration[$layer] = $data; - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - } - return true; - } - - /** - * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini - * @return true|PEAR_Error - */ - function readFTPConfigFile($path) - { - do { // poor man's try - if (!class_exists('PEAR_FTP')) { - if (!class_exists('PEAR_Common')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Common.php'; - } - if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { - require_once 'phar://go-pear.phar/' . 'PEAR/FTP.php'; - } - } - - if (!class_exists('PEAR_FTP')) { - return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); - } - - $this->_ftp = &new PEAR_FTP; - $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); - $e = $this->_ftp->init($path); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - $tmp = System::mktemp('-d'); - PEAR_Common::addTempFile($tmp); - $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . - 'pear.ini', false, FTP_BINARY); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); - $this->_ftp->disconnect(); - $this->_ftp->popErrorHandling(); - $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; - $e = $this->readConfigFile(null, 'ftp'); - if (PEAR::isError($e)) { - return $e; - } - - $fail = array(); - foreach ($this->configuration_info as $key => $val) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - // any directory configs must be set for this to work - if (!isset($this->configuration['ftp'][$key])) { - $fail[] = $key; - } - } - } - - if (!count($fail)) { - return true; - } - - $fail = '"' . implode('", "', $fail) . '"'; - unset($this->files['ftp']); - unset($this->configuration['ftp']); - return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . - 'directory configuration variables. These variables were not set: ' . - $fail); - } while (false); // poor man's catch - unset($this->files['ftp']); - return PEAR::raiseError('no remote host specified'); - } - - /** - * Reads the existing configurations and creates the _channels array from it - */ - function _setupChannels() - { - $set = array_flip(array_values($this->_channels)); - foreach ($this->configuration as $layer => $data) { - $i = 1000; - if (isset($data['__channels']) && is_array($data['__channels'])) { - foreach ($data['__channels'] as $channel => $info) { - $set[$channel] = $i++; - } - } - } - $this->_channels = array_values(array_flip($set)); - $this->setChannels($this->_channels); - } - - function deleteChannel($channel) - { - $ch = strtolower($channel); - foreach ($this->configuration as $layer => $data) { - if (isset($data['__channels']) && isset($data['__channels'][$ch])) { - unset($this->configuration[$layer]['__channels'][$ch]); - } - } - - $this->_channels = array_flip($this->_channels); - unset($this->_channels[$ch]); - $this->_channels = array_flip($this->_channels); - } - - /** - * Merges data into a config layer from a file. Does the same - * thing as readConfigFile, except it does not replace all - * existing values in the config layer. - * @param string file to read from - * @param bool whether to overwrite existing data (default TRUE) - * @param string config layer to insert data into ('user' or 'system') - * @param string if true, errors are returned if file opening fails - * @return bool TRUE on success or a PEAR error on failure - */ - function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) - { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; - } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; - } - - $this->_decodeInput($data); - if ($override) { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); - } else { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); - } - - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - } - return true; - } - - /** - * @param array - * @param array - * @return array - * @static - */ - function arrayMergeRecursive($arr2, $arr1) - { - $ret = array(); - foreach ($arr2 as $key => $data) { - if (!isset($arr1[$key])) { - $ret[$key] = $data; - unset($arr1[$key]); - continue; - } - if (is_array($data)) { - if (!is_array($arr1[$key])) { - $ret[$key] = $arr1[$key]; - unset($arr1[$key]); - continue; - } - $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); - unset($arr1[$key]); - } - } - - return array_merge($ret, $arr1); - } - - /** - * Writes data into a config layer from a file. - * - * @param string|null file to read from, or null for default - * @param string config layer to insert data into ('user' or - * 'system') - * @param string|null data to write to config file or null for internal data [DEPRECATED] - * @return bool TRUE on success or a PEAR error on failure - */ - function writeConfigFile($file = null, $layer = 'user', $data = null) - { - $this->_lazyChannelSetup($layer); - if ($layer == 'both' || $layer == 'all') { - foreach ($this->files as $type => $file) { - $err = $this->writeConfigFile($file, $type, $data); - if (PEAR::isError($err)) { - return $err; - } - } - return true; - } - - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config file type `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = ($data === null) ? $this->configuration[$layer] : $data; - $this->_encodeOutput($data); - $opt = array('-p', dirname($file)); - if (!@System::mkDir($opt)) { - return $this->raiseError("could not create directory: " . dirname($file)); - } - - if (file_exists($file) && is_file($file) && !is_writeable($file)) { - return $this->raiseError("no write access to $file!"); - } - - $fp = @fopen($file, "w"); - if (!$fp) { - return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); - } - - $contents = "#PEAR_Config 0.9\n" . serialize($data); - if (!@fwrite($fp, $contents)) { - return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); - } - return true; - } - - /** - * Reads configuration data from a file and returns the parsed data - * in an array. - * - * @param string file to read from - * @return array configuration data or a PEAR error on failure - * @access private - */ - function _readConfigDataFrom($file) - { - $fp = false; - if (file_exists($file)) { - $fp = @fopen($file, "r"); - } - - if (!$fp) { - return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); - } - - $size = filesize($file); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fclose($fp); - $contents = file_get_contents($file); - if (empty($contents)) { - return $this->raiseError('Configuration file "' . $file . '" is empty'); - } - - set_magic_quotes_runtime($rt); - - $version = false; - if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { - $version = $matches[1]; - $contents = substr($contents, strlen($matches[0])); - } else { - // Museum config file - if (substr($contents,0,2) == 'a:') { - $version = '0.1'; - } - } - - if ($version && version_compare("$version", '1', '<')) { - // no '@', it is possible that unserialize - // raises a notice but it seems to block IO to - // STDOUT if a '@' is used and a notice is raise - $data = unserialize($contents); - - if (!is_array($data) && !$data) { - if ($contents == serialize(false)) { - $data = array(); - } else { - $err = $this->raiseError("PEAR_Config: bad data in $file"); - return $err; - } - } - if (!is_array($data)) { - if (strlen(trim($contents)) > 0) { - $error = "PEAR_Config: bad data in $file"; - $err = $this->raiseError($error); - return $err; - } - - $data = array(); - } - // add parsing of newer formats here... - } else { - $err = $this->raiseError("$file: unknown version `$version'"); - return $err; - } - - return $data; - } - - /** - * Gets the file used for storing the config for a layer - * - * @param string $layer 'user' or 'system' - */ - function getConfFile($layer) - { - return $this->files[$layer]; - } - - /** - * @param string Configuration class name, used for detecting duplicate calls - * @param array information on a role as parsed from its xml file - * @return true|PEAR_Error - * @access private - */ - function _addConfigVars($class, $vars) - { - static $called = array(); - if (isset($called[$class])) { - return; - } - - $called[$class] = 1; - if (count($vars) > 3) { - return $this->raiseError('Roles can only define 3 new config variables or less'); - } - - foreach ($vars as $name => $var) { - if (!is_array($var)) { - return $this->raiseError('Configuration information must be an array'); - } - - if (!isset($var['type'])) { - return $this->raiseError('Configuration information must contain a type'); - } elseif (!in_array($var['type'], - array('string', 'mask', 'password', 'directory', 'file', 'set'))) { - return $this->raiseError( - 'Configuration type must be one of directory, file, string, ' . - 'mask, set, or password'); - } - if (!isset($var['default'])) { - return $this->raiseError( - 'Configuration information must contain a default value ("default" index)'); - } - - if (is_array($var['default'])) { - $real_default = ''; - foreach ($var['default'] as $config_var => $val) { - if (strpos($config_var, 'text') === 0) { - $real_default .= $val; - } elseif (strpos($config_var, 'constant') === 0) { - if (!defined($val)) { - return $this->raiseError( - 'Unknown constant "' . $val . '" requested in ' . - 'default value for configuration variable "' . - $name . '"'); - } - - $real_default .= constant($val); - } elseif (isset($this->configuration_info[$config_var])) { - $real_default .= - $this->configuration_info[$config_var]['default']; - } else { - return $this->raiseError( - 'Unknown request for "' . $config_var . '" value in ' . - 'default value for configuration variable "' . - $name . '"'); - } - } - $var['default'] = $real_default; - } - - if ($var['type'] == 'integer') { - $var['default'] = (integer) $var['default']; - } - - if (!isset($var['doc'])) { - return $this->raiseError( - 'Configuration information must contain a summary ("doc" index)'); - } - - if (!isset($var['prompt'])) { - return $this->raiseError( - 'Configuration information must contain a simple prompt ("prompt" index)'); - } - - if (!isset($var['group'])) { - return $this->raiseError( - 'Configuration information must contain a simple group ("group" index)'); - } - - if (isset($this->configuration_info[$name])) { - return $this->raiseError('Configuration variable "' . $name . - '" already exists'); - } - - $this->configuration_info[$name] = $var; - // fix bug #7351: setting custom config variable in a channel fails - $this->_channelConfigInfo[] = $name; - } - - return true; - } - - /** - * Encodes/scrambles configuration data before writing to files. - * Currently, 'password' values will be base64-encoded as to avoid - * that people spot cleartext passwords by accident. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private - */ - function _encodeOutput(&$data) - { - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_encodeOutput($data['__channels'][$channel]); - } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - // we base64-encode passwords so they are at least - // not shown in plain by accident - case 'password': { - $data[$key] = base64_encode($data[$key]); - break; - } - case 'mask': { - $data[$key] = octdec($data[$key]); - break; - } - } - } - - return true; - } - - /** - * Decodes/unscrambles configuration data after reading from files. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private - * - * @see PEAR_Config::_encodeOutput - */ - function _decodeInput(&$data) - { - if (!is_array($data)) { - return true; - } - - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_decodeInput($data['__channels'][$channel]); - } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - case 'password': { - $data[$key] = base64_decode($data[$key]); - break; - } - case 'mask': { - $data[$key] = decoct($data[$key]); - break; - } - } - } - - return true; - } - - /** - * Retrieve the default channel. - * - * On startup, channels are not initialized, so if the default channel is not - * pear.php.net, then initialize the config. - * @param string registry layer - * @return string|false - */ - function getDefaultChannel($layer = null) - { - $ret = false; - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - break; - } - } - } elseif (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - } - - if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { - $ret = 'pecl.php.net'; - } - - if ($ret) { - if ($ret != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - - return $ret; - } - - return PEAR_CONFIG_DEFAULT_CHANNEL; - } - - /** - * Returns a configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access public - */ - function get($key, $layer = null, $channel = false) - { - if (!isset($this->configuration_info[$key])) { - return null; - } - - if ($key == '__channels') { - return null; - } - - if ($key == 'default_channel') { - return $this->getDefaultChannel($layer); - } - - if (!$channel) { - $channel = $this->getDefaultChannel(); - } elseif ($channel != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - $channel = strtolower($channel); - - $test = (in_array($key, $this->_channelConfigInfo)) ? - $this->_getChannelValue($key, $layer, $channel) : - null; - if ($test !== null) { - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - return $test; - } - - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } - - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } - } - } - return $test; - } - } - } elseif (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } - - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } - } - } - - return $test; - } - - return null; - } - - /** - * Returns a channel-specific configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access private - */ - function _getChannelValue($key, $layer, $channel) - { - if ($key == '__channels' || $channel == 'pear.php.net') { - return null; - } - - $ret = null; - if ($layer === null) { - foreach ($this->layers as $ilayer) { - if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; - break; - } - } - } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$layer]['__channels'][$channel][$key]; - } - - if ($key != 'preferred_mirror') { - return $ret; - } - - - if ($ret !== null) { - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } - - if (!$chan->getMirror($ret) && $chan->getName() != $ret) { - return $channel; // mirror does not exist - } - } - - return $ret; - } - - if ($channel != $this->getDefaultChannel($layer)) { - return $channel; // we must use the channel name as the preferred mirror - // if the user has not chosen an alternate - } - - return $this->getDefaultChannel($layer); - } - - /** - * Set a config value in a specific layer (defaults to 'user'). - * Enforces the types defined in the configuration_info array. An - * integer config variable will be cast to int, and a set config - * variable will be validated against its legal values. - * - * @param string config key - * @param string config value - * @param string (optional) config layer - * @param string channel to set this value for, or null for global value - * @return bool TRUE on success, FALSE on failure - */ - function set($key, $value, $layer = 'user', $channel = false) - { - if ($key == '__channels') { - return false; - } - - if (!isset($this->configuration[$layer])) { - return false; - } - - if ($key == 'default_channel') { - // can only set this value globally - $channel = 'pear.php.net'; - if ($value != 'pear.php.net') { - $this->_lazyChannelSetup($layer); - } - } - - if ($key == 'preferred_mirror') { - if ($channel == '__uri') { - return false; // can't set the __uri pseudo-channel's mirror - } - - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); - if (PEAR::isError($chan)) { - return false; - } - - if (!$chan->getMirror($value) && $chan->getName() != $value) { - return false; // mirror does not exist - } - } - } - - if (!isset($this->configuration_info[$key])) { - return false; - } - - extract($this->configuration_info[$key]); - switch ($type) { - case 'integer': - $value = (int)$value; - break; - case 'set': { - // If a valid_set is specified, require the value to - // be in the set. If there is no valid_set, accept - // any value. - if ($valid_set) { - reset($valid_set); - if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || - (key($valid_set) !== 0 && empty($valid_set[$value]))) - { - return false; - } - } - break; - } - } - - if (!$channel) { - $channel = $this->get('default_channel', null, 'pear.php.net'); - } - - if (!in_array($channel, $this->_channels)) { - $this->_lazyChannelSetup($layer); - $reg = &$this->getRegistry($layer); - if ($reg) { - $channel = $reg->channelName($channel); - } - - if (!in_array($channel, $this->_channels)) { - return false; - } - } - - if ($channel != 'pear.php.net') { - if (in_array($key, $this->_channelConfigInfo)) { - $this->configuration[$layer]['__channels'][$channel][$key] = $value; - return true; - } - - return false; - } - - if ($key == 'default_channel') { - if (!isset($reg)) { - $reg = &$this->getRegistry($layer); - if (!$reg) { - $reg = &$this->getRegistry(); - } - } - - if ($reg) { - $value = $reg->channelName($value); - } - - if (!$value) { - return false; - } - } - - $this->configuration[$layer][$key] = $value; - if ($key == 'php_dir' && !$this->_noRegistry) { - if (!isset($this->_registry[$layer]) || - $value != $this->_registry[$layer]->install_dir) { - $this->_registry[$layer] = &new PEAR_Registry($value); - $this->_regInitialized[$layer] = false; - $this->_registry[$layer]->setConfig($this, false); - } - } - - return true; - } - - function _lazyChannelSetup($uselayer = false) - { - if ($this->_noRegistry) { - return; - } - - $merge = false; - foreach ($this->_registry as $layer => $p) { - if ($uselayer && $uselayer != $layer) { - continue; - } - - if (!$this->_regInitialized[$layer]) { - if ($layer == 'default' && isset($this->_registry['user']) || - isset($this->_registry['system'])) { - // only use the default registry if there are no alternatives - continue; - } - - if (!is_object($this->_registry[$layer])) { - if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - return; - } - } - - $this->setChannels($this->_registry[$layer]->listChannels(), $merge); - $this->_regInitialized[$layer] = true; - $merge = true; - } - } - } - - /** - * Set the list of channels. - * - * This should be set via a call to {@link PEAR_Registry::listChannels()} - * @param array - * @param bool - * @return bool success of operation - */ - function setChannels($channels, $merge = false) - { - if (!is_array($channels)) { - return false; - } - - if ($merge) { - $this->_channels = array_merge($this->_channels, $channels); - } else { - $this->_channels = $channels; - } - - foreach ($channels as $channel) { - $channel = strtolower($channel); - if ($channel == 'pear.php.net') { - continue; - } - - foreach ($this->layers as $layer) { - if (!isset($this->configuration[$layer]['__channels'])) { - $this->configuration[$layer]['__channels'] = array(); - } - if (!isset($this->configuration[$layer]['__channels'][$channel]) - || !is_array($this->configuration[$layer]['__channels'][$channel])) { - $this->configuration[$layer]['__channels'][$channel] = array(); - } - } - } - - return true; - } - - /** - * Get the type of a config value. - * - * @param string config key - * - * @return string type, one of "string", "integer", "file", - * "directory", "set" or "password". - * - * @access public - * - */ - function getType($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['type']; - } - return false; - } - - /** - * Get the documentation for a config value. - * - * @param string config key - * @return string documentation string - * - * @access public - * - */ - function getDocs($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['doc']; - } - - return false; - } - - /** - * Get the short documentation for a config value. - * - * @param string config key - * @return string short documentation string - * - * @access public - * - */ - function getPrompt($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['prompt']; - } - - return false; - } - - /** - * Get the parameter group for a config key. - * - * @param string config key - * @return string parameter group - * - * @access public - * - */ - function getGroup($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['group']; - } - - return false; - } - - /** - * Get the list of parameter groups. - * - * @return array list of parameter groups - * - * @access public - * - */ - function getGroups() - { - $tmp = array(); - foreach ($this->configuration_info as $key => $info) { - $tmp[$info['group']] = 1; - } - - return array_keys($tmp); - } - - /** - * Get the list of the parameters in a group. - * - * @param string $group parameter group - * @return array list of parameters in $group - * - * @access public - * - */ - function getGroupKeys($group) - { - $keys = array(); - foreach ($this->configuration_info as $key => $info) { - if ($info['group'] == $group) { - $keys[] = $key; - } - } - - return $keys; - } - - /** - * Get the list of allowed set values for a config value. Returns - * NULL for config values that are not sets. - * - * @param string config key - * @return array enumerated array of set values, or NULL if the - * config key is unknown or not a set - * - * @access public - * - */ - function getSetValues($key) - { - if (isset($this->configuration_info[$key]) && - isset($this->configuration_info[$key]['type']) && - $this->configuration_info[$key]['type'] == 'set') - { - $valid_set = $this->configuration_info[$key]['valid_set']; - reset($valid_set); - if (key($valid_set) === 0) { - return $valid_set; - } - - return array_keys($valid_set); - } - - return null; - } - - /** - * Get all the current config keys. - * - * @return array simple array of config keys - * - * @access public - */ - function getKeys() - { - $keys = array(); - foreach ($this->layers as $layer) { - $test = $this->configuration[$layer]; - if (isset($test['__channels'])) { - foreach ($test['__channels'] as $channel => $configs) { - $keys = array_merge($keys, $configs); - } - } - - unset($test['__channels']); - $keys = array_merge($keys, $test); - - } - return array_keys($keys); - } - - /** - * Remove the a config key from a specific config layer. - * - * @param string config key - * @param string (optional) config layer - * @param string (optional) channel (defaults to default channel) - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function remove($key, $layer = 'user', $channel = null) - { - if ($channel === null) { - $channel = $this->getDefaultChannel(); - } - - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - unset($this->configuration[$layer]['__channels'][$channel][$key]); - return true; - } - } - - if (isset($this->configuration[$layer][$key])) { - unset($this->configuration[$layer][$key]); - return true; - } - - return false; - } - - /** - * Temporarily remove an entire config layer. USE WITH CARE! - * - * @param string config key - * @param string (optional) config layer - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function removeLayer($layer) - { - if (isset($this->configuration[$layer])) { - $this->configuration[$layer] = array(); - return true; - } - - return false; - } - - /** - * Stores configuration data in a layer. - * - * @param string config layer to store - * @return bool TRUE on success, or PEAR error on failure - * - * @access public - */ - function store($layer = 'user', $data = null) - { - return $this->writeConfigFile(null, $layer, $data); - } - - /** - * Tells what config layer that gets to define a key. - * - * @param string config key - * @param boolean return the defining channel - * - * @return string|array the config layer, or an empty string if not found. - * - * if $returnchannel, the return is an array array('layer' => layername, - * 'channel' => channelname), or an empty string if not found - * - * @access public - */ - function definedBy($key, $returnchannel = false) - { - foreach ($this->layers as $layer) { - $channel = $this->getDefaultChannel(); - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => $channel); - } - return $layer; - } - } - - if (isset($this->configuration[$layer][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => 'pear.php.net'); - } - return $layer; - } - } - - return ''; - } - - /** - * Tells whether a given key exists as a config value. - * - * @param string config key - * @return bool whether exists in this object - * - * @access public - */ - function isDefined($key) - { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - return true; - } - } - - return false; - } - - /** - * Tells whether a given config layer exists. - * - * @param string config layer - * @return bool whether exists in this object - * - * @access public - */ - function isDefinedLayer($layer) - { - return isset($this->configuration[$layer]); - } - - /** - * Returns the layers defined (except the 'default' one) - * - * @return array of the defined layers - */ - function getLayers() - { - $cf = $this->configuration; - unset($cf['default']); - return array_keys($cf); - } - - function apiVersion() - { - return '1.1'; - } - - /** - * @return PEAR_Registry - */ - function &getRegistry($use = null) - { - $layer = $use === null ? 'user' : $use; - if (isset($this->_registry[$layer])) { - return $this->_registry[$layer]; - } elseif ($use === null && isset($this->_registry['system'])) { - return $this->_registry['system']; - } elseif ($use === null && isset($this->_registry['default'])) { - return $this->_registry['default']; - } elseif ($use) { - $a = false; - return $a; - } - - // only go here if null was passed in - echo "CRITICAL ERROR: Registry could not be initialized from any value"; - exit(1); - } - - /** - * This is to allow customization like the use of installroot - * @param PEAR_Registry - * @return bool - */ - function setRegistry(&$reg, $layer = 'user') - { - if ($this->_noRegistry) { - return false; - } - - if (!in_array($layer, array('user', 'system'))) { - return false; - } - - $this->_registry[$layer] = &$reg; - if (is_object($reg)) { - $this->_registry[$layer]->setConfig($this, false); - } - - return true; - } - - function noRegistry() - { - $this->_noRegistry = true; - } - - /** - * @return PEAR_REST - */ - function &getREST($version, $options = array()) - { - $version = str_replace('.', '', $version); - if (!class_exists($class = 'PEAR_REST_' . $version)) { - require_once 'phar://go-pear.phar/' . 'PEAR/REST/' . $version . '.php'; - } - - $remote = &new $class($this, $options); - return $remote; - } - - /** - * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a - * remote configuration file has been specified - * @return PEAR_FTP|false - */ - function &getFTP() - { - if (isset($this->_ftp)) { - return $this->_ftp; - } - - $a = false; - return $a; - } - - function _prependPath($path, $prepend) - { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; - } - } - return $path; - } - - /** - * @param string|false installation directory to prepend to all _dir variables, or false to - * disable - */ - function setInstallRoot($root) - { - if (substr($root, -1) == DIRECTORY_SEPARATOR) { - $root = substr($root, 0, -1); - } - $old = $this->_installRoot; - $this->_installRoot = $root; - if (($old != $root) && !$this->_noRegistry) { - foreach (array_keys($this->_registry) as $layer) { - if ($layer == 'ftp' || !isset($this->_registry[$layer])) { - continue; - } - $this->_registry[$layer] = - &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } - } - } -} - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Dependency2.php 286494 2009-07-29 06:57:11Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Required for the PEAR_VALIDATE_* constants - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php'; - -/** - * Dependency check for PEAR packages - * - * This class handles both version 1.0 and 2.0 dependencies - * WARNING: *any* changes to this class must be duplicated in the - * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, - * or unit tests will not actually validate the changes - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Dependency2 -{ - /** - * One of the PEAR_VALIDATE_* states - * @see PEAR_VALIDATE_NORMAL - * @var integer - */ - var $_state; - - /** - * Command-line options to install/upgrade/uninstall commands - * @param array - */ - var $_options; - - /** - * @var OS_Guess - */ - var $_os; - - /** - * @var PEAR_Registry - */ - var $_registry; - - /** - * @var PEAR_Config - */ - var $_config; - - /** - * @var PEAR_DependencyDB - */ - var $_dependencydb; - - /** - * Output of PEAR_Registry::parsedPackageName() - * @var array - */ - var $_currentPackage; - - /** - * @param PEAR_Config - * @param array installation options - * @param array format of PEAR_Registry::parsedPackageName() - * @param int installation state (one of PEAR_VALIDATE_*) - */ - function PEAR_Dependency2(&$config, $installoptions, $package, - $state = PEAR_VALIDATE_INSTALLING) - { - $this->_config = &$config; - if (!class_exists('PEAR_DependencyDB')) { - require_once 'phar://go-pear.phar/' . 'PEAR/DependencyDB.php'; - } - - if (isset($installoptions['packagingroot'])) { - // make sure depdb is in the right location - $config->setInstallRoot($installoptions['packagingroot']); - } - - $this->_registry = &$config->getRegistry(); - $this->_dependencydb = &PEAR_DependencyDB::singleton($config); - if (isset($installoptions['packagingroot'])) { - $config->setInstallRoot(false); - } - - $this->_options = $installoptions; - $this->_state = $state; - if (!class_exists('OS_Guess')) { - require_once 'phar://go-pear.phar/' . 'OS/Guess.php'; - } - - $this->_os = new OS_Guess; - $this->_currentPackage = $package; - } - - function _getExtraString($dep) - { - $extra = ' ('; - if (isset($dep['uri'])) { - return ''; - } - - if (isset($dep['recommended'])) { - $extra .= 'recommended version ' . $dep['recommended']; - } else { - if (isset($dep['min'])) { - $extra .= 'version >= ' . $dep['min']; - } - - if (isset($dep['max'])) { - if ($extra != ' (') { - $extra .= ', '; - } - $extra .= 'version <= ' . $dep['max']; - } - - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if ($extra != ' (') { - $extra .= ', '; - } - - $extra .= 'excluded versions: '; - foreach ($dep['exclude'] as $i => $exclude) { - if ($i) { - $extra .= ', '; - } - $extra .= $exclude; - } - } - } - - $extra .= ')'; - if ($extra == ' ()') { - $extra = ''; - } - - return $extra; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function getPHP_OS() - { - return PHP_OS; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function getsysname() - { - return $this->_os->getSysname(); - } - - /** - * Specify a dependency on an OS. Use arch for detailed os/processor information - * - * There are two generic OS dependencies that will be the most common, unix and windows. - * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix - */ - function validateOsDependency($dep) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - if ($dep['name'] == '*') { - return true; - } - - $not = isset($dep['conflicts']) ? true : false; - switch (strtolower($dep['name'])) { - case 'windows' : - if ($not) { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on Windows"); - } - - return $this->warning("warning: Cannot install %s on Windows"); - } - } else { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on Windows"); - } - - return $this->warning("warning: Can only install %s on Windows"); - } - } - break; - case 'unix' : - $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); - if ($not) { - if (in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on any Unix system"); - } - - return $this->warning( "warning: Cannot install %s on any Unix system"); - } - } else { - if (!in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on a Unix system"); - } - - return $this->warning("warning: Can only install %s on a Unix system"); - } - } - break; - default : - if ($not) { - if (strtolower($dep['name']) == strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . $dep['name'] . - ' operating system'); - } - - return $this->warning('warning: Cannot install %s on ' . - $dep['name'] . ' operating system'); - } - } else { - if (strtolower($dep['name']) != strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } - - return $this->warning('warning: Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } - } - } - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function matchSignature($pattern) - { - return $this->_os->matchSignature($pattern); - } - - /** - * Specify a complex dependency on an OS/processor/kernel version, - * Use OS for simple operating system dependency. - * - * This is the only dependency that accepts an eregable pattern. The pattern - * will be matched against the php_uname() output parsed by OS_Guess - */ - function validateArchDependency($dep) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING) { - return true; - } - - $not = isset($dep['conflicts']) ? true : false; - if (!$this->matchSignature($dep['pattern'])) { - if (!$not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, does not ' . - 'match "' . $dep['pattern'] . '"'); - } - - return $this->warning('warning: %s Architecture dependency failed, does ' . - 'not match "' . $dep['pattern'] . '"'); - } - - return true; - } - - if ($not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, required "' . - $dep['pattern'] . '"'); - } - - return $this->warning('warning: %s Architecture dependency failed, ' . - 'required "' . $dep['pattern'] . '"'); - } - - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function extension_loaded($name) - { - return extension_loaded($name); - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function phpversion($name = null) - { - if ($name !== null) { - return phpversion($name); - } - - return phpversion(); - } - - function validateExtensionDependency($dep, $required = true) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - $loaded = $this->extension_loaded($dep['name']); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } - - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude']) - ) { - if ($loaded) { - if (isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return true; - } - - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return $this->warning('warning: %s requires PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); - } - - if (!$loaded) { - if (isset($dep['conflicts'])) { - return true; - } - - if (!$required) { - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } - - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } - - $version = (string) $this->phpversion($dep['name']); - if (empty($version)) { - $version = '0'; - } - - $fail = false; - if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { - $fail = true; - } - - if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { - $fail = true; - } - - if ($fail && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (isset($dep['conflicts'])) { - continue; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } - - return $this->warning('warning: %s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - } - } - - if (isset($dep['recommended'])) { - if (version_compare($version, $dep['recommended'], '==')) { - return true; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . - ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'] . - '", but may be compatible, use --force to install'); - } - - return $this->warning('warning: %s dependency: PHP extension ' . - $dep['name'] . ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'].'"'); - } - - return true; - } - - function validatePhpDependency($dep) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - $version = $this->phpversion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } - - if (isset($dep['min'])) { - if (!version_compare($version, $dep['min'], '>=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } - } - - if (isset($dep['max'])) { - if (!version_compare($version, $dep['max'], '<=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } - } - - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP version ' . - $exclude); - } - - return $this->warning( - 'warning: %s is not compatible with PHP version ' . - $exclude); - } - } - } - - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function getPEARVersion() - { - return '1.9.0'; - } - - function validatePearinstallerDependency($dep) - { - $pearversion = $this->getPEARVersion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } - - if (version_compare($pearversion, $dep['min'], '<')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - - if (isset($dep['max'])) { - if (version_compare($pearversion, $dep['max'], '>')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - } - - if (isset($dep['exclude'])) { - if (!isset($dep['exclude'][0])) { - $dep['exclude'] = array($dep['exclude']); - } - - foreach ($dep['exclude'] as $exclude) { - if (version_compare($exclude, $pearversion, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PEAR Installer ' . - 'version ' . $exclude); - } - - return $this->warning('warning: %s is not compatible with PEAR ' . - 'Installer version ' . $exclude); - } - } - } - - return true; - } - - function validateSubpackageDependency($dep, $required, $params) - { - return $this->validatePackageDependency($dep, $required, $params); - } - - /** - * @param array dependency information (2.0 format) - * @param boolean whether this is a required dependency - * @param array a list of downloaded packages to be installed, if any - * @param boolean if true, then deps on pear.php.net that fail will also check - * against pecl.php.net packages to accomodate extensions that have - * moved to pecl.php.net from pear.php.net - */ - function validatePackageDependency($dep, $required, $params, $depv1 = false) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - if (isset($dep['providesextension'])) { - if ($this->extension_loaded($dep['providesextension'])) { - $save = $dep; - $subdep = $dep; - $subdep['name'] = $subdep['providesextension']; - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->validateExtensionDependency($subdep, $required); - PEAR::popErrorHandling(); - if (!PEAR::isError($ret)) { - return true; - } - } - } - - if ($this->_state == PEAR_VALIDATE_INSTALLING) { - return $this->_validatePackageInstall($dep, $required, $depv1); - } - - if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { - return $this->_validatePackageDownload($dep, $required, $params, $depv1); - } - } - - function _validatePackageDownload($dep, $required, $params, $depv1 = false) - { - $dep['package'] = $dep['name']; - if (isset($dep['uri'])) { - $dep['channel'] = '__uri'; - } - - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $found = false; - foreach ($params as $param) { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => $dep['channel']))) { - $found = true; - break; - } - - if ($depv1 && $dep['channel'] == 'pear.php.net') { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => 'pecl.php.net'))) { - $found = true; - break; - } - } - } - - if (!$found && isset($dep['providesextension'])) { - foreach ($params as $param) { - if ($param->isExtension($dep['providesextension'])) { - $found = true; - break; - } - } - } - - if ($found) { - $version = $param->getVersion(); - $installed = false; - $downloaded = true; - } else { - if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - $dep['channel']); - } else { - if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], - 'pear.php.net')) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - 'pear.php.net'); - } else { - $version = 'not installed or downloaded'; - $installed = false; - $downloaded = false; - } - } - } - - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude']) - ) { - if ($installed || $downloaded) { - $installed = $installed ? 'installed' : 'downloaded'; - if (isset($dep['conflicts'])) { - $rest = ''; - if ($version) { - $rest = ", $installed version is " . $version; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); - } - - return true; - } - - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); - } - - if (!$installed && !$downloaded) { - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); - } - - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { - $fail = true; - } - - if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { - $fail = true; - } - - if ($fail && !isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - $dep['package'] = $dep['name']; - $dep = $this->_registry->parsedPackageNameToString($dep, true); - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && - isset($dep['conflicts']) && !isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . - ", $installed version is " . $version); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - if (isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force']) - ) { - return $this->raiseError('%s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } - - return $this->warning('warning: %s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - } - } - - if (isset($dep['recommended'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (version_compare($version, $dep['recommended'], '==')) { - return true; - } - - if (!$found && $installed) { - $param = $this->_registry->getPackage($dep['name'], $dep['channel']); - } - - if ($param) { - $found = false; - foreach ($params as $parent) { - if ($parent->isEqual($this->_currentPackage)) { - $found = true; - break; - } - } - - if ($found) { - if ($param->isCompatible($parent)) { - return true; - } - } else { // this is for validPackage() calls - $parent = $this->_registry->getPackage($this->_currentPackage['package'], - $this->_currentPackage['channel']); - if ($parent !== null && $param->isCompatible($parent)) { - return true; - } - } - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && - !isset($this->_options['loose']) - ) { - return $this->raiseError('%s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended'] . - ', but may be compatible, use --force to install'); - } - - return $this->warning('warning: %s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended']); - } - - return true; - } - - function _validatePackageInstall($dep, $required, $depv1 = false) - { - return $this->_validatePackageDownload($dep, $required, array(), $depv1); - } - - /** - * Verify that uninstalling packages passed in to command line is OK. - * - * @param PEAR_Installer $dl - * @return PEAR_Error|true - */ - function validatePackageUninstall(&$dl) - { - if (PEAR::isError($this->_dependencydb)) { - return $this->_dependencydb; - } - - $params = array(); - // construct an array of "downloaded" packages to fool the package dependency checker - // into using these to validate uninstalls of circular dependencies - $downloaded = &$dl->getUninstallPackages(); - foreach ($downloaded as $i => $pf) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php'; - } - $dp = &new PEAR_Downloader_Package($dl); - $dp->setPackageFile($downloaded[$i]); - $params[$i] = &$dp; - } - - // check cache - $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . - strtolower($this->_currentPackage['package']); - if (isset($dl->___uninstall_package_cache)) { - $badpackages = $dl->___uninstall_package_cache; - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } - } - - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); - } - - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } - - return true; - } - - // first, list the immediate parents of each package to be uninstalled - $perpackagelist = array(); - $allparents = array(); - foreach ($params as $i => $param) { - $a = array( - 'channel' => strtolower($param->getChannel()), - 'package' => strtolower($param->getPackage()) - ); - - $deps = $this->_dependencydb->getDependentPackages($a); - if ($deps) { - foreach ($deps as $d) { - $pardeps = $this->_dependencydb->getDependencies($d); - foreach ($pardeps as $dep) { - if (strtolower($dep['dep']['channel']) == $a['channel'] && - strtolower($dep['dep']['name']) == $a['package']) { - if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { - $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); - } - $perpackagelist[$a['channel'] . '/' . $a['package']][] - = array($d['channel'] . '/' . $d['package'], $dep); - if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { - $allparents[$d['channel'] . '/' . $d['package']] = array(); - } - if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { - $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); - } - $allparents[$d['channel'] . '/' . $d['package']] - [$a['channel'] . '/' . $a['package']][] - = array($d, $dep); - } - } - } - } - } - - // next, remove any packages from the parents list that are not installed - $remove = array(); - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { - continue; - } - $remove[$parent] = true; - } - } - - // next remove any packages from the parents list that are not passed in for - // uninstallation - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - foreach ($params as $param) { - if (strtolower($param->getChannel()) == $d[0][0]['channel'] && - strtolower($param->getPackage()) == $d[0][0]['package']) { - // found it - continue 3; - } - } - $remove[$parent] = true; - } - } - - // remove all packages whose dependencies fail - // save which ones failed for error reporting - $badchildren = array(); - do { - $fail = false; - foreach ($remove as $package => $unused) { - if (!isset($allparents[$package])) { - continue; - } - - foreach ($allparents[$package] as $kid => $d1) { - foreach ($d1 as $depinfo) { - if ($depinfo[1]['type'] != 'optional') { - if (isset($badchildren[$kid])) { - continue; - } - $badchildren[$kid] = true; - $remove[$kid] = true; - $fail = true; - continue 2; - } - } - } - if ($fail) { - // start over, we removed some children - continue 2; - } - } - } while ($fail); - - // next, construct the list of packages that can't be uninstalled - $badpackages = array(); - $save = $this->_currentPackage; - foreach ($perpackagelist as $package => $packagedeps) { - foreach ($packagedeps as $parent) { - if (!isset($remove[$parent[0]])) { - continue; - } - - $packagename = $this->_registry->parsePackageName($parent[0]); - $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); - $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); - $packagename['package'] = $pa->getPackage(); - $this->_currentPackage = $packagename; - // parent is not present in uninstall list, make sure we can actually - // uninstall it (parent dep is optional) - $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); - $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); - $parentname['package'] = $pa->getPackage(); - $parent[1]['dep']['package'] = $parentname['package']; - $parent[1]['dep']['channel'] = $parentname['channel']; - if ($parent[1]['type'] == 'optional') { - $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); - if ($test !== true) { - $badpackages[$package]['warnings'][] = $test; - } - } else { - $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); - if ($test !== true) { - $badpackages[$package]['errors'][] = $test; - } - } - } - } - - $this->_currentPackage = $save; - $dl->___uninstall_package_cache = $badpackages; - if (isset($badpackages[$memyselfandI])) { - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } - } - - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); - } - - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } - } - - return true; - } - - function _validatePackageUninstall($dep, $required, $dl) - { - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); - if (!$version) { - return true; - } - - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if (isset($dep['conflicts'])) { - return true; // uninstall OK - these packages conflict (probably installed with --force) - } - - if (!isset($dep['min']) && !isset($dep['max'])) { - if (!$required) { - return $this->warning('"' . $depname . '" can be optionally used by ' . - 'installed package %s' . $extra); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('"' . $depname . '" is required by ' . - 'installed package %s' . $extra); - } - - return $this->warning('warning: "' . $depname . '" is required by ' . - 'installed package %s' . $extra); - } - - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { - $fail = true; - } - - if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { - $fail = true; - } - - // we re-use this variable, preserve the original value - $saverequired = $required; - if (!$required) { - return $this->warning($depname . $extra . ' can be optionally used by installed package' . - ' "%s"'); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError($depname . $extra . ' is required by installed package' . - ' "%s"'); - } - - return $this->raiseError('warning: ' . $depname . $extra . - ' is required by installed package "%s"'); - } - - /** - * validate a downloaded package against installed packages - * - * As of PEAR 1.4.3, this will only validate - * - * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * $pkg package identifier (either - * array('package' => blah, 'channel' => blah) or an array with - * index 'info' referencing an object) - * @param PEAR_Downloader $dl - * @param array $params full list of packages to install - * @return true|PEAR_Error - */ - function validatePackage($pkg, &$dl, $params = array()) - { - if (is_array($pkg) && isset($pkg['info'])) { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); - } else { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); - } - - $fail = false; - if ($deps) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php'; - } - - $dp = &new PEAR_Downloader_Package($dl); - if (is_object($pkg)) { - $dp->setPackageFile($pkg); - } else { - $dp->setDownloadURL($pkg); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($deps as $channel => $info) { - foreach ($info as $package => $ds) { - foreach ($params as $packd) { - if (strtolower($packd->getPackage()) == strtolower($package) && - $packd->getChannel() == $channel) { - $dl->log(3, 'skipping installed package check of "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $channel, 'package' => $package), - true) . - '", version "' . $packd->getVersion() . '" will be ' . - 'downloaded and installed'); - continue 2; // jump to next package - } - } - - foreach ($ds as $d) { - $checker = &new PEAR_Dependency2($this->_config, $this->_options, - array('channel' => $channel, 'package' => $package), $this->_state); - $dep = $d['dep']; - $required = $d['type'] == 'required'; - $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); - if (is_array($ret)) { - $dl->log(0, $ret[0]); - } elseif (PEAR::isError($ret)) { - $dl->log(0, $ret->getMessage()); - $fail = true; - } - } - } - } - PEAR::popErrorHandling(); - } - - if ($fail) { - return $this->raiseError( - '%s cannot be installed, conflicts with installed packages'); - } - - return true; - } - - /** - * validate a package.xml 1.0 dependency - */ - function validateDependency1($dep, $params = array()) - { - if (!isset($dep['optional'])) { - $dep['optional'] = 'no'; - } - - list($newdep, $type) = $this->normalizeDep($dep); - if (!$newdep) { - return $this->raiseError("Invalid Dependency"); - } - - if (method_exists($this, "validate{$type}Dependency")) { - return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', - $params, true); - } - } - - /** - * Convert a 1.0 dep into a 2.0 dep - */ - function normalizeDep($dep) - { - $types = array( - 'pkg' => 'Package', - 'ext' => 'Extension', - 'os' => 'Os', - 'php' => 'Php' - ); - - if (!isset($types[$dep['type']])) { - return array(false, false); - } - - $type = $types[$dep['type']]; - - $newdep = array(); - switch ($type) { - case 'Package' : - $newdep['channel'] = 'pear.php.net'; - case 'Extension' : - case 'Os' : - $newdep['name'] = $dep['name']; - break; - } - - $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); - switch ($dep['rel']) { - case 'has' : - return array($newdep, $type); - break; - case 'not' : - $newdep['conflicts'] = true; - break; - case '>=' : - case '>' : - $newdep['min'] = $dep['version']; - if ($dep['rel'] == '>') { - $newdep['exclude'] = $dep['version']; - } - break; - case '<=' : - case '<' : - $newdep['max'] = $dep['version']; - if ($dep['rel'] == '<') { - $newdep['exclude'] = $dep['version']; - } - break; - case 'ne' : - case '!=' : - $newdep['min'] = '0'; - $newdep['max'] = '100000'; - $newdep['exclude'] = $dep['version']; - break; - case '==' : - $newdep['min'] = $dep['version']; - $newdep['max'] = $dep['version']; - break; - } - if ($type == 'Php') { - if (!isset($newdep['min'])) { - $newdep['min'] = '4.4.0'; - } - - if (!isset($newdep['max'])) { - $newdep['max'] = '6.0.0'; - } - } - return array($newdep, $type); - } - - /** - * Converts text comparing operators to them sign equivalents - * - * Example: 'ge' to '>=' - * - * @access public - * @param string Operator - * @return string Sign equivalent - */ - function signOperator($operator) - { - switch($operator) { - case 'lt': return '<'; - case 'le': return '<='; - case 'gt': return '>'; - case 'ge': return '>='; - case 'eq': return '=='; - case 'ne': return '!='; - default: - return $operator; - } - } - - function raiseError($msg) - { - if (isset($this->_options['ignore-errors'])) { - return $this->warning($msg); - } - - return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } - - function warning($msg) - { - return array(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: DependencyDB.php 286686 2009-08-02 17:38:57Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Needed for error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Config.php'; - -$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); -/** - * Track dependency relationships between installed packages - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_DependencyDB -{ - // {{{ properties - - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Config - * @access private - */ - var $_config; - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Registry - * @access private - */ - var $_registry; - /** - * Filename of the dependency DB (usually .depdb) - * @var string - * @access private - */ - var $_depdb = false; - /** - * File name of the lockfile (usually .depdblock) - * @var string - * @access private - */ - var $_lockfile = false; - /** - * Open file resource for locking the lockfile - * @var resource|false - * @access private - */ - var $_lockFp = false; - /** - * API version of this class, used to validate a file on-disk - * @var string - * @access private - */ - var $_version = '1.0'; - /** - * Cached dependency database file - * @var array|null - * @access private - */ - var $_cache; - - // }}} - // {{{ & singleton() - - /** - * Get a raw dependency database. Calls setConfig() and assertDepsDB() - * @param PEAR_Config - * @param string|false full path to the dependency database, or false to use default - * @return PEAR_DependencyDB|PEAR_Error - * @static - */ - function &singleton(&$config, $depdb = false) - { - $phpdir = $config->get('php_dir', null, 'pear.php.net'); - if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { - $a = new PEAR_DependencyDB; - $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; - $a->setConfig($config, $depdb); - $e = $a->assertDepsDB(); - if (PEAR::isError($e)) { - return $e; - } - } - - return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; - } - - /** - * Set up the registry/location of dependency DB - * @param PEAR_Config|false - * @param string|false full path to the dependency database, or false to use default - */ - function setConfig(&$config, $depdb = false) - { - if (!$config) { - $this->_config = &PEAR_Config::singleton(); - } else { - $this->_config = &$config; - } - - $this->_registry = &$this->_config->getRegistry(); - if (!$depdb) { - $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'; - } else { - $this->_depdb = $depdb; - } - - $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; - } - // }}} - - function hasWriteAccess() - { - if (!file_exists($this->_depdb)) { - $dir = $this->_depdb; - while ($dir && $dir != '.') { - $dir = dirname($dir); // cd .. - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - } - - return false; - } - - return is_writeable($this->_depdb); - } - - // {{{ assertDepsDB() - - /** - * Create the dependency database, if it doesn't exist. Error if the database is - * newer than the code reading it. - * @return void|PEAR_Error - */ - function assertDepsDB() - { - if (!is_file($this->_depdb)) { - $this->rebuildDB(); - return; - } - - $depdb = $this->_getDepDB(); - // Datatype format has been changed, rebuild the Deps DB - if ($depdb['_version'] < $this->_version) { - $this->rebuildDB(); - } - - if ($depdb['_version']{0} > $this->_version{0}) { - return PEAR::raiseError('Dependency database is version ' . - $depdb['_version'] . ', and we are version ' . - $this->_version . ', cannot continue'); - } - } - - /** - * Get a list of installed packages that depend on this package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependentPackages(&$pkg) - { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (isset($data['packages'][$channel][$package])) { - return $data['packages'][$channel][$package]; - } - - return false; - } - - /** - * Get a list of the actual dependencies of installed packages that depend on - * a package. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependentPackageDependencies(&$pkg) - { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $depend = $this->getDependentPackages($pkg); - if (!$depend) { - return false; - } - - $dependencies = array(); - foreach ($depend as $info) { - $temp = $this->getDependencies($info); - foreach ($temp as $dep) { - if ( - isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && - strtolower($dep['dep']['channel']) == $channel && - strtolower($dep['dep']['name']) == $package - ) { - if (!isset($dependencies[$info['channel']])) { - $dependencies[$info['channel']] = array(); - } - - if (!isset($dependencies[$info['channel']][$info['package']])) { - $dependencies[$info['channel']][$info['package']] = array(); - } - $dependencies[$info['channel']][$info['package']][] = $dep; - } - } - } - - return $dependencies; - } - - /** - * Get a list of dependencies of this installed package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependencies(&$pkg) - { - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $data = $this->_getDepDB(); - if (isset($data['dependencies'][$channel][$package])) { - return $data['dependencies'][$channel][$package]; - } - - return false; - } - - /** - * Determine whether $parent depends on $child, near or deep - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 - */ - function dependsOn($parent, $child) - { - $c = array(); - $this->_getDepDB(); - return $this->_dependsOn($parent, $child, $c); - } - - function _dependsOn($parent, $child, &$checked) - { - if (is_object($parent)) { - $channel = strtolower($parent->getChannel()); - $package = strtolower($parent->getPackage()); - } else { - $channel = strtolower($parent['channel']); - $package = strtolower($parent['package']); - } - - if (is_object($child)) { - $depchannel = strtolower($child->getChannel()); - $deppackage = strtolower($child->getPackage()); - } else { - $depchannel = strtolower($child['channel']); - $deppackage = strtolower($child['package']); - } - - if (isset($checked[$channel][$package][$depchannel][$deppackage])) { - return false; // avoid endless recursion - } - - $checked[$channel][$package][$depchannel][$deppackage] = true; - if (!isset($this->_cache['dependencies'][$channel][$package])) { - return false; - } - - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if (is_object($child)) { - if ($info['dep']['uri'] == $child->getURI()) { - return true; - } - } elseif (isset($child['uri'])) { - if ($info['dep']['uri'] == $child['uri']) { - return true; - } - } - return false; - } - - if (strtolower($info['dep']['channel']) == $depchannel && - strtolower($info['dep']['name']) == $deppackage) { - return true; - } - } - - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if ($this->_dependsOn(array( - 'uri' => $info['dep']['uri'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; - } - } else { - if ($this->_dependsOn(array( - 'channel' => $info['dep']['channel'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; - } - } - } - - return false; - } - - /** - * Register dependencies of a package that is being installed or upgraded - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 - */ - function installPackage(&$package) - { - $data = $this->_getDepDB(); - unset($this->_cache); - $this->_setPackageDeps($data, $package); - $this->_writeDepDB($data); - } - - /** - * Remove dependencies of a package that is being uninstalled, or upgraded. - * - * Upgraded packages first uninstall, then install - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have - * indices 'channel' and 'package' - */ - function uninstallPackage(&$pkg) - { - $data = $this->_getDepDB(); - unset($this->_cache); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (!isset($data['dependencies'][$channel][$package])) { - return true; - } - - foreach ($data['dependencies'][$channel][$package] as $dep) { - $found = false; - $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); - $depname = strtolower($dep['dep']['name']); - if (isset($data['packages'][$depchannel][$depname])) { - foreach ($data['packages'][$depchannel][$depname] as $i => $info) { - if ($info['channel'] == $channel && $info['package'] == $package) { - $found = true; - break; - } - } - } - - if ($found) { - unset($data['packages'][$depchannel][$depname][$i]); - if (!count($data['packages'][$depchannel][$depname])) { - unset($data['packages'][$depchannel][$depname]); - if (!count($data['packages'][$depchannel])) { - unset($data['packages'][$depchannel]); - } - } else { - $data['packages'][$depchannel][$depname] = - array_values($data['packages'][$depchannel][$depname]); - } - } - } - - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } - - if (!count($data['dependencies'])) { - unset($data['dependencies']); - } - - if (!count($data['packages'])) { - unset($data['packages']); - } - - $this->_writeDepDB($data); - } - - /** - * Rebuild the dependency DB by reading registry entries. - * @return true|PEAR_Error - */ - function rebuildDB() - { - $depdb = array('_version' => $this->_version); - if (!$this->hasWriteAccess()) { - // allow startup for read-only with older Registry - return $depdb; - } - - $packages = $this->_registry->listAllPackages(); - if (PEAR::isError($packages)) { - return $packages; - } - - foreach ($packages as $channel => $ps) { - foreach ($ps as $package) { - $package = $this->_registry->getPackage($package, $channel); - if (PEAR::isError($package)) { - return $package; - } - $this->_setPackageDeps($depdb, $package); - } - } - - $error = $this->_writeDepDB($depdb); - if (PEAR::isError($error)) { - return $error; - } - - $this->_cache = $depdb; - return true; - } - - /** - * Register usage of the dependency DB to prevent race conditions - * @param int one of the LOCK_* constants - * @return true|PEAR_Error - * @access private - */ - function _lock($mode = LOCK_EX) - { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->_lockFp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH) { - if (!file_exists($this->_lockfile)) { - touch($this->_lockfile); - } elseif (!is_file($this->_lockfile)) { - return PEAR::raiseError('could not create Dependency lock file, ' . - 'it exists and is not a regular file'); - } - $open_mode = 'r'; - } - - if (!is_resource($this->_lockFp)) { - $this->_lockFp = @fopen($this->_lockfile, $open_mode); - } - - if (!is_resource($this->_lockFp)) { - return PEAR::raiseError("could not create Dependency lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->_lockFp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); - } - - return true; - } - - /** - * Release usage of dependency DB - * @return true|PEAR_Error - * @access private - */ - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->_lockFp)) { - fclose($this->_lockFp); - } - $this->_lockFp = null; - return $ret; - } - - /** - * Load the dependency database from disk, or return the cache - * @return array|PEAR_Error - */ - function _getDepDB() - { - if (!$this->hasWriteAccess()) { - return array('_version' => $this->_version); - } - - if (isset($this->_cache)) { - return $this->_cache; - } - - if (!$fp = fopen($this->_depdb, 'r')) { - $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); - return $err; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - fclose($fp); - $data = unserialize(file_get_contents($this->_depdb)); - set_magic_quotes_runtime($rt); - $this->_cache = $data; - return $data; - } - - /** - * Write out the dependency database to disk - * @param array the database - * @return true|PEAR_Error - * @access private - */ - function _writeDepDB(&$deps) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - if (!$fp = fopen($this->_depdb, 'wb')) { - $this->_unlock(); - return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fwrite($fp, serialize($deps)); - set_magic_quotes_runtime($rt); - fclose($fp); - $this->_unlock(); - $this->_cache = $deps; - return true; - } - - /** - * Register all dependencies from a package in the dependencies database, in essence - * "installing" the package's dependency information - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @access private - */ - function _setPackageDeps(&$data, &$pkg) - { - $pkg->setConfig($this->_config); - if ($pkg->getPackagexmlVersion() == '1.0') { - $gen = &$pkg->getDefaultGenerator(); - $deps = $gen->dependenciesToV2(); - } else { - $deps = $pkg->getDeps(true); - } - - if (!$deps) { - return; - } - - if (!is_array($data)) { - $data = array(); - } - - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); - } - - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } - - $data['dependencies'][$channel][$package] = array(); - if (isset($deps['required']['package'])) { - if (!isset($deps['required']['package'][0])) { - $deps['required']['package'] = array($deps['required']['package']); - } - - foreach ($deps['required']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); - } - } - - if (isset($deps['optional']['package'])) { - if (!isset($deps['optional']['package'][0])) { - $deps['optional']['package'] = array($deps['optional']['package']); - } - - foreach ($deps['optional']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } - } - - if (isset($deps['required']['subpackage'])) { - if (!isset($deps['required']['subpackage'][0])) { - $deps['required']['subpackage'] = array($deps['required']['subpackage']); - } - - foreach ($deps['required']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); - } - } - - if (isset($deps['optional']['subpackage'])) { - if (!isset($deps['optional']['subpackage'][0])) { - $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); - } - - foreach ($deps['optional']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } - } - - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - foreach ($deps['group'] as $group) { - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - - foreach ($group['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } - - foreach ($group['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - } - } - - if ($data['dependencies'][$channel][$package] == array()) { - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } - } - } - - /** - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array the specific dependency - * @param required|optional whether this is a required or an optional dep - * @param string|false dependency group this dependency is from, or false for ordinary dep - */ - function _registerDep(&$data, &$pkg, $dep, $type, $group = false) - { - $info = array( - 'dep' => $dep, - 'type' => $type, - 'group' => $group - ); - - $dep = array_map('strtolower', $dep); - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); - } - - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } - - if (!isset($data['dependencies'][$channel][$package])) { - $data['dependencies'][$channel][$package] = array(); - } - - $data['dependencies'][$channel][$package][] = $info; - if (isset($data['packages'][$depchannel][$dep['name']])) { - $found = false; - foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { - if ($p['channel'] == $channel && $p['package'] == $package) { - $found = true; - break; - } - } - } else { - if (!isset($data['packages'])) { - $data['packages'] = array(); - } - - if (!isset($data['packages'][$depchannel])) { - $data['packages'][$depchannel] = array(); - } - - if (!isset($data['packages'][$depchannel][$dep['name']])) { - $data['packages'][$depchannel][$dep['name']] = array(); - } - - $found = false; - } - - if (!$found) { - $data['packages'][$depchannel][$dep['name']][] = array( - 'channel' => $channel, - 'package' => $package - ); - } - } -} - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Downloader.php 287109 2009-08-11 18:50:30Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.0 - */ - -/** - * Needed for constants, extending - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Common.php'; - -define('PEAR_INSTALLER_OK', 1); -define('PEAR_INSTALLER_FAILED', 0); -define('PEAR_INSTALLER_SKIPPED', -1); -define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); - -/** - * Administration class used to download anything from the internet (PEAR Packages, - * static URLs, xml files) - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.0 - */ -class PEAR_Downloader extends PEAR_Common -{ - /** - * @var PEAR_Registry - * @access private - */ - var $_registry; - - /** - * Preferred Installation State (snapshot, devel, alpha, beta, stable) - * @var string|null - * @access private - */ - var $_preferredState; - - /** - * Options from command-line passed to Install. - * - * Recognized options:
    - * - onlyreqdeps : install all required dependencies as well - * - alldeps : install all dependencies, including optional - * - installroot : base relative path to install files in - * - force : force a download even if warnings would prevent it - * - nocompress : download uncompressed tarballs - * @see PEAR_Command_Install - * @access private - * @var array - */ - var $_options; - - /** - * Downloaded Packages after a call to download(). - * - * Format of each entry: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @access private - * @var array - */ - var $_downloadedPackages = array(); - - /** - * Packages slated for download. - * - * This is used to prevent downloading a package more than once should it be a dependency - * for two packages to be installed. - * Format of each entry: - * - *
    -     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
    -     * );
    -     * 
    - * @access private - * @var array - */ - var $_toDownload = array(); - - /** - * Array of every package installed, with names lower-cased. - * - * Format: - * - * array('package1' => 0, 'package2' => 1, ); - * - * @var array - */ - var $_installed = array(); - - /** - * @var array - * @access private - */ - var $_errorStack = array(); - - /** - * @var boolean - * @access private - */ - var $_internalDownload = false; - - /** - * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} - * @var array - * @access private - */ - var $_packageSortTree; - - /** - * Temporary directory, or configuration value where downloads will occur - * @var string - */ - var $_downloadDir; - - /** - * @param PEAR_Frontend_* - * @param array - * @param PEAR_Config - */ - function PEAR_Downloader(&$ui, $options, &$config) - { - parent::PEAR_Common(); - $this->_options = $options; - $this->config = &$config; - $this->_preferredState = $this->config->get('preferred_state'); - $this->ui = &$ui; - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; - } - - if (isset($this->_options['installroot'])) { - $this->config->setInstallRoot($this->_options['installroot']); - } - $this->_registry = &$config->getRegistry(); - - if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { - $this->_installed = $this->_registry->listAllPackages(); - foreach ($this->_installed as $key => $unused) { - if (!count($unused)) { - continue; - } - $strtolower = create_function('$a','return strtolower($a);'); - array_walk($this->_installed[$key], $strtolower); - } - } - } - - /** - * Attempt to discover a channel's remote capabilities from - * its server name - * @param string - * @return boolean - */ - function discover($channel) - { - $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $callback = $this->ui ? array(&$this, '_downloadCallback') : null; - if (!class_exists('System')) { - require_once 'phar://go-pear.phar/' . 'System.php'; - } - - $tmp = System::mktemp(array('-d')); - $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - // Attempt to fallback to https automatically. - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); - $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - return false; - } - } - - list($a, $lastmodified) = $a; - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $b = new PEAR_ChannelFile; - if ($b->fromXmlFile($a)) { - unlink($a); - if ($this->config->get('auto_discover')) { - $this->_registry->addChannel($b, $lastmodified); - $alias = $b->getName(); - if ($b->getName() == $this->_registry->channelName($b->getAlias())) { - $alias = $b->getAlias(); - } - - $this->log(1, 'Auto-discovered channel "' . $channel . - '", alias "' . $alias . '", adding to registry'); - } - - return true; - } - - unlink($a); - return false; - } - - /** - * For simpler unit-testing - * @param PEAR_Downloader - * @return PEAR_Downloader_Package - */ - function &newDownloaderPackage(&$t) - { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php'; - } - $a = &new PEAR_Downloader_Package($t); - return $a; - } - - /** - * For simpler unit-testing - * @param PEAR_Config - * @param array - * @param array - * @param int - */ - function &getDependency2Object(&$c, $i, $p, $s) - { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - $z = &new PEAR_Dependency2($c, $i, $p, $s); - return $z; - } - - function &download($params) - { - if (!count($params)) { - $a = array(); - return $a; - } - - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } - - $channelschecked = array(); - // convert all parameters into PEAR_Downloader_Package objects - foreach ($params as $i => $param) { - $params[$i] = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $params[$i]->initialize($param); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - continue; - } - - if (PEAR::isError($err)) { - if (!isset($this->_options['soft']) && $err->getMessage() !== '') { - $this->log(0, $err->getMessage()); - } - - $params[$i] = false; - if (is_object($param)) { - $param = $param->getChannel() . '/' . $param->getPackage(); - } - - if (!isset($this->_options['soft'])) { - $this->log(2, 'Package "' . $param . '" is not valid'); - } - - // Message logged above in a specific verbose mode, passing null to not show up on CLI - $this->pushError(null, PEAR_INSTALLER_SKIPPED); - } else { - do { - if ($params[$i] && $params[$i]->getType() == 'local') { - // bug #7090 skip channel.xml check for local packages - break; - } - - if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && - !isset($this->_options['offline']) - ) { - $channelschecked[$params[$i]->getChannel()] = true; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('System')) { - require_once 'phar://go-pear.phar/' . 'System.php'; - } - - $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); - if (PEAR::isError($curchannel)) { - PEAR::staticPopErrorHandling(); - return $this->raiseError($curchannel); - } - - if (PEAR::isError($dir = $this->getDownloadDir())) { - PEAR::staticPopErrorHandling(); - break; - } - - $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel()); - $url = 'http://' . $mirror . '/channel.xml'; - $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified()); - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - // Attempt fallback to https automatically - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $a = $this->downloadHttp('https://' . $mirror . - '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - break; - } - } - $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . - 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . - '" to update'); - } - } while (false); - - if ($params[$i] && !isset($this->_options['downloadonly'])) { - if (isset($this->_options['packagingroot'])) { - $checkdir = $this->_prependPath( - $this->config->get('php_dir', null, $params[$i]->getChannel()), - $this->_options['packagingroot']); - } else { - $checkdir = $this->config->get('php_dir', - null, $params[$i]->getChannel()); - } - - while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { - $checkdir = dirname($checkdir); - } - - if ($checkdir == '.') { - $checkdir = '/'; - } - - if (!is_writeable($checkdir)) { - return PEAR::raiseError('Cannot install, php_dir for channel "' . - $params[$i]->getChannel() . '" is not writeable by the current user'); - } - } - } - } - - unset($channelschecked); - PEAR_Downloader_Package::removeDuplicates($params); - if (!count($params)) { - $a = array(); - return $a; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { - $reverify = true; - while ($reverify) { - $reverify = false; - foreach ($params as $i => $param) { - //PHP Bug 40768 / PEAR Bug #10944 - //Nested foreaches fail in PHP 5.2.1 - key($params); - $ret = $params[$i]->detectDependencies($params); - if (PEAR::isError($ret)) { - $reverify = true; - $params[$i] = false; - PEAR_Downloader_Package::removeDuplicates($params); - if (!isset($this->_options['soft'])) { - $this->log(0, $ret->getMessage()); - } - continue 2; - } - } - } - } - - if (isset($this->_options['offline'])) { - $this->log(3, 'Skipping dependency download check, --offline specified'); - } - - if (!count($params)) { - $a = array(); - return $a; - } - - while (PEAR_Downloader_Package::mergeDependencies($params)); - PEAR_Downloader_Package::removeDuplicates($params, true); - $errorparams = array(); - if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { - if (count($errorparams)) { - foreach ($errorparams as $param) { - $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); - $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); - } - $a = array(); - return $a; - } - } - - PEAR_Downloader_Package::removeInstalled($params); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($params); - PEAR::popErrorHandling(); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } - - $ret = array(); - $newparams = array(); - if (isset($this->_options['pretend'])) { - return $params; - } - - $somefailed = false; - foreach ($params as $i => $package) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$params[$i]->download(); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (!isset($this->_options['soft'])) { - $this->log(1, $pf->getMessage()); - $this->log(0, 'Error: cannot download "' . - $this->_registry->parsedPackageNameToString($package->getParsedPackage(), - true) . - '"'); - } - $somefailed = true; - continue; - } - - $newparams[] = &$params[$i]; - $ret[] = array( - 'file' => $pf->getArchiveFile(), - 'info' => &$pf, - 'pkg' => $pf->getPackage() - ); - } - - if ($somefailed) { - // remove params that did not download successfully - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($newparams, true); - PEAR::popErrorHandling(); - if (!count($newparams)) { - $this->pushError('Download failed', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } - } - - $this->_downloadedPackages = $ret; - return $newparams; - } - - /** - * @param array all packages to be installed - */ - function analyzeDependencies(&$params, $force = false) - { - $hasfailed = $failed = false; - if (isset($this->_options['downloadonly'])) { - return; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $redo = true; - $reset = false; - while ($redo) { - $redo = false; - foreach ($params as $i => $param) { - $deps = $param->getDeps(); - if (!$deps) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); - - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - continue; - } - - if (!$reset && $param->alreadyValidated() && !$force) { - continue; - } - - if (count($deps)) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); - if ($send === null) { - $send = $param->getDownloadURL(); - } - - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - - $failed = false; - if (isset($deps['required'])) { - foreach ($deps['required'] as $type => $dep) { - // note: Dependency2 will never return a PEAR_Error if ignore-errors - // is specified, so soft is needed to turn off logging - if (!isset($dep[0])) { - if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - - if (isset($deps['optional'])) { - foreach ($deps['optional'] as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - - $groupname = $param->getGroup(); - if (isset($deps['group']) && $groupname) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - $found = false; - foreach ($deps['group'] as $group) { - if ($group['attribs']['name'] == $groupname) { - $found = true; - break; - } - } - - if ($found) { - unset($group['attribs']); - foreach ($group as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - } - } else { - foreach ($deps as $dep) { - if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - $params[$i]->setValidated(); - } - - if ($failed) { - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - } - } - PEAR::staticPopErrorHandling(); - if ($hasfailed && (isset($this->_options['ignore-errors']) || - isset($this->_options['nodeps']))) { - // this is probably not needed, but just in case - if (!isset($this->_options['soft'])) { - $this->log(0, 'WARNING: dependencies failed'); - } - } - } - - /** - * Retrieve the directory that downloads will happen in - * @access private - * @return string - */ - function getDownloadDir() - { - if (isset($this->_downloadDir)) { - return $this->_downloadDir; - } - $downloaddir = $this->config->get('download_dir'); - if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { - if (is_dir($downloaddir) && !is_writable($downloaddir)) { - $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir to avoid this warning'); - } - if (!class_exists('System')) { - require_once 'phar://go-pear.phar/' . 'System.php'; - } - if (PEAR::isError($downloaddir = System::mktemp('-d'))) { - return $downloaddir; - } - $this->log(3, '+ tmp dir created at ' . $downloaddir); - } - if (!is_writable($downloaddir)) { - if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || - !is_writable($downloaddir)) { - return PEAR::raiseError('download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } - } - return $this->_downloadDir = $downloaddir; - } - - function setDownloadDir($dir) - { - if (!@is_writable($dir)) { - if (PEAR::isError(System::mkdir(array('-p', $dir)))) { - return PEAR::raiseError('download directory "' . $dir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } - } - $this->_downloadDir = $dir; - } - - function configSet($key, $value, $layer = 'user', $channel = false) - { - $this->config->set($key, $value, $layer, $channel); - $this->_preferredState = $this->config->get('preferred_state', null, $channel); - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; - } - } - - function setOptions($options) - { - $this->_options = $options; - } - - // }}} - // {{{ setOptions() - function getOptions() - { - return $this->_options; - } - - /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string - */ - function &getPackagefileObject(&$c, $d, $t = false) - { - if (!class_exists('PEAR_PackageFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php'; - } - $a = &new PEAR_PackageFile($c, $d, $t); - return $a; - } - - /** - * @param array output of {@link parsePackageName()} - * @access private - */ - function _getPackageDownloadUrl($parr) - { - $curchannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $parr['channel']); - // getDownloadURL returns an array. On error, it only contains information - // on the latest release as array(version, info). On success it contains - // array(version, info, download url string) - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (!$this->_registry->channelExists($parr['channel'])) { - do { - if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { - break; - } - - $this->configSet('default_channel', $curchannel); - return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); - } while (false); - } - - $chan = &$this->_registry->getChannel($parr['channel']); - if (PEAR::isError($chan)) { - return $chan; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); - $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); - // package is installed - use the installed release stability level - if (!isset($parr['state']) && $stability !== null) { - $state = $stability['release']; - } - PEAR::staticPopErrorHandling(); - $base2 = false; - - $preferred_mirror = $this->config->get('preferred_mirror'); - if (!$chan->supportsREST($preferred_mirror) || - ( - !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) - && - !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - ) { - return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); - } - - if ($base2) { - $rest = &$this->config->getREST('1.3', $this->_options); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', $this->_options); - } - - $downloadVersion = false; - if (!isset($parr['version']) && !isset($parr['state']) && $version - && !PEAR::isError($version) - && !isset($this->_options['downloadonly']) - ) { - $downloadVersion = $version; - } - - $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName()); - if (PEAR::isError($url)) { - $this->configSet('default_channel', $curchannel); - return $url; - } - - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); - } - - if (!is_array($url)) { - return $url; - } - - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); - } - - if (!isset($this->_options['force']) && - !isset($this->_options['downloadonly']) && - $version && - !PEAR::isError($version) && - !isset($parr['group']) - ) { - if (version_compare($version, $url['version'], '=')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is the same as the ' . - 'released version ' . $url['version'], -976); - } - - if (version_compare($version, $url['version'], '>')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is newer than detected ' . - 'released version ' . $url['version'], -976); - } - } - - if (isset($url['info']['required']) || $url['compatible']) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($parr['channel']); - if ($url['compatible']) { - $pf->setRawCompatible($url['compatible']); - } - } else { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php'; - $pf = new PEAR_PackageFile_v1; - } - - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); - } - - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } - - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; - } - - return $url; - } - - /** - * @param array dependency array - * @access private - */ - function _getDepPackageDownloadUrl($dep, $parr) - { - $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; - $curchannel = $this->config->get('default_channel'); - if (isset($dep['uri'])) { - $xsdversion = '2.0'; - $chan = &$this->_registry->getChannel('__uri'); - if (PEAR::isError($chan)) { - return $chan; - } - - $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); - $this->configSet('default_channel', '__uri'); - } else { - if (isset($dep['channel'])) { - $remotechannel = $dep['channel']; - } else { - $remotechannel = 'pear.php.net'; - } - - if (!$this->_registry->channelExists($remotechannel)) { - do { - if ($this->config->get('auto_discover')) { - if ($this->discover($remotechannel)) { - break; - } - } - return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); - } while (false); - } - - $chan = &$this->_registry->getChannel($remotechannel); - if (PEAR::isError($chan)) { - return $chan; - } - - $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); - $this->configSet('default_channel', $remotechannel); - } - - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (isset($parr['state']) && isset($parr['version'])) { - unset($parr['state']); - } - - if (isset($dep['uri'])) { - $info = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $info->initialize($dep); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - return PEAR::raiseError('Cannot initialize dependency'); - } - - if (PEAR::isError($err)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $err->getMessage()); - } - - if (is_object($info)) { - $param = $info->getChannel() . '/' . $info->getPackage(); - } - return PEAR::raiseError('Package "' . $param . '" is not valid'); - } - return $info; - } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) - && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) - ) { - $rest = &$this->config->getREST('1.0', $this->_options); - $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, - $state, $version, $chan->getName()); - if (PEAR::isError($url)) { - return $url; - } - - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); - } - - if (!is_array($url)) { - return $url; - } - - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); - } - - if (isset($url['info']['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; - } - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($remotechannel); - } else { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - - } - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); - } - - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } - - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; - } - - return $url; - } - - return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); - } - - /** - * @deprecated in favor of _getPackageDownloadUrl - */ - function getPackageDownloadUrl($package, $version = null, $channel = false) - { - if ($version) { - $package .= "-$version"; - } - if ($this === null || $this->_registry === null) { - $package = "http://pear.php.net/get/$package"; - } else { - $chan = $this->_registry->getChannel($channel); - if (PEAR::isError($chan)) { - return ''; - } - $package = "http://" . $chan->getServer() . "/get/$package"; - } - if (!extension_loaded("zlib")) { - $package .= '?uncompress=yes'; - } - return $package; - } - - /** - * Retrieve a list of downloaded packages after a call to {@link download()}. - * - * Also resets the list of downloaded packages. - * @return array - */ - function getDownloadedPackages() - { - $ret = $this->_downloadedPackages; - $this->_downloadedPackages = array(); - $this->_toDownload = array(); - return $ret; - } - - function _downloadCallback($msg, $params = null) - { - switch ($msg) { - case 'saveas': - $this->log(1, "downloading $params ..."); - break; - case 'done': - $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); - break; - case 'bytesread': - static $bytes; - if (empty($bytes)) { - $bytes = 0; - } - if (!($bytes % 10240)) { - $this->log(1, '.', false); - } - $bytes += $params; - break; - case 'start': - if($params[1] == -1) { - $length = "Unknown size"; - } else { - $length = number_format($params[1], 0, '', ',')." bytes"; - } - $this->log(1, "Starting to download {$params[0]} ($length)"); - break; - } - if (method_exists($this->ui, '_downloadCallback')) - $this->ui->_downloadCallback($msg, $params); - } - - function _prependPath($path, $prepend) - { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; - } - } - return $path; - } - - /** - * @param string - * @param integer - */ - function pushError($errmsg, $code = -1) - { - array_push($this->_errorStack, array($errmsg, $code)); - } - - function getErrorMsgs() - { - $msgs = array(); - $errs = $this->_errorStack; - foreach ($errs as $err) { - $msgs[] = $err[0]; - } - $this->_errorStack = array(); - return $msgs; - } - - /** - * for BC - * - * @deprecated - */ - function sortPkgDeps(&$packages, $uninstall = false) - { - $uninstall ? - $this->sortPackagesForUninstall($packages) : - $this->sortPackagesForInstall($packages); - } - - /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * This uses the topological sort method from graph theory, and the - * Structures_Graph package to properly sort dependencies for installation. - * @param array an array of downloaded PEAR_Downloader_Packages - * @return array array of array(packagefilename, package.xml contents) - */ - function sortPackagesForInstall(&$packages) - { - require_once 'phar://go-pear.phar/' . 'Structures/Graph.php'; - require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php'; - require_once 'phar://go-pear.phar/' . 'Structures/Graph/Manipulator/TopologicalSorter.php'; - $depgraph = new Structures_Graph(true); - $nodes = array(); - $reg = &$this->config->getRegistry(); - foreach ($packages as $i => $package) { - $pname = $reg->parsedPackageNameToString( - array( - 'channel' => $package->getChannel(), - 'package' => strtolower($package->getPackage()), - )); - $nodes[$pname] = new Structures_Graph_Node; - $nodes[$pname]->setData($packages[$i]); - $depgraph->addNode($nodes[$pname]); - } - - $deplinks = array(); - foreach ($nodes as $package => $node) { - $pf = &$node->getData(); - $pdeps = $pf->getDeps(true); - if (!$pdeps) { - continue; - } - - if ($pf->getPackagexmlVersion() == '1.0') { - foreach ($pdeps as $dep) { - if ($dep['type'] != 'pkg' || - (isset($dep['optional']) && $dep['optional'] == 'yes')) { - continue; - } - - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pear.php.net', - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } - - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } - - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pecl.php.net', - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } - - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } - } - } else { - // the only ordering we care about is: - // 1) subpackages must be installed before packages that depend on them - // 2) required deps must be installed before packages that depend on them - if (isset($pdeps['required']['subpackage'])) { - $t = $pdeps['required']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } - - foreach ($pdeps['group'] as $group) { - if (isset($group['subpackage'])) { - $t = $group['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } - } - - if (isset($pdeps['optional']['subpackage'])) { - $t = $pdeps['optional']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['required']['package'])) { - $t = $pdeps['required']['package']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } - - foreach ($pdeps['group'] as $group) { - if (isset($group['package'])) { - $t = $group['package']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } - } - } - } - - $this->_detectDepCycle($deplinks); - foreach ($deplinks as $dependent => $parents) { - foreach ($parents as $parent => $unused) { - $nodes[$dependent]->connectTo($nodes[$parent]); - } - } - - $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); - $ret = array(); - for ($i = 0, $count = count($installOrder); $i < $count; $i++) { - foreach ($installOrder[$i] as $index => $sortedpackage) { - $data = &$installOrder[$i][$index]->getData(); - $ret[] = &$nodes[$reg->parsedPackageNameToString( - array( - 'channel' => $data->getChannel(), - 'package' => strtolower($data->getPackage()), - ))]->getData(); - } - } - - $packages = $ret; - return; - } - - /** - * Detect recursive links between dependencies and break the cycles - * - * @param array - * @access private - */ - function _detectDepCycle(&$deplinks) - { - do { - $keepgoing = false; - foreach ($deplinks as $dep => $parents) { - foreach ($parents as $parent => $unused) { - // reset the parent cycle detector - $this->_testCycle(null, null, null); - if ($this->_testCycle($dep, $deplinks, $parent)) { - $keepgoing = true; - unset($deplinks[$dep][$parent]); - if (count($deplinks[$dep]) == 0) { - unset($deplinks[$dep]); - } - - continue 3; - } - } - } - } while ($keepgoing); - } - - function _testCycle($test, $deplinks, $dep) - { - static $visited = array(); - if ($test === null) { - $visited = array(); - return; - } - - // this happens when a parent has a dep cycle on another dependency - // but the child is not part of the cycle - if (isset($visited[$dep])) { - return false; - } - - $visited[$dep] = 1; - if ($test == $dep) { - return true; - } - - if (isset($deplinks[$dep])) { - if (in_array($test, array_keys($deplinks[$dep]), true)) { - return true; - } - - foreach ($deplinks[$dep] as $parent => $unused) { - if ($this->_testCycle($test, $deplinks, $parent)) { - return true; - } - } - } - - return false; - } - - /** - * Set up the dependency for installation parsing - * - * @param array $t dependency information - * @param PEAR_Registry $reg - * @param array $deplinks list of dependency links already established - * @param array $nodes all existing package nodes - * @param string $package parent package name - * @access private - */ - function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) - { - foreach ($t as $dep) { - $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => $depchannel, - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } - $deplinks[$dname][$package] = 1; - } - } - } - - function _dependsOn($a, $b) - { - return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); - } - - function _checkDepTree($channel, $package, $b, $checked = array()) - { - $checked[$channel][$package] = true; - if (!isset($this->_depTree[$channel][$package])) { - return false; - } - - if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] - [strtolower($b->getPackage())])) { - return true; - } - - foreach ($this->_depTree[$channel][$package] as $ch => $packages) { - foreach ($packages as $pa => $true) { - if ($this->_checkDepTree($ch, $pa, $b, $checked)) { - return true; - } - } - } - - return false; - } - - function _sortInstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return 1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return -1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependsOn($a, $b)) { - return 1; - } - if ($this->_dependsOn($b, $a)) { - return -1; - } - return 0; - } - - /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP/SSL connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir directory to save file in - * @param mixed $callback function/method to call for status - * updates - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @param false|string $channel Channel to use for retrieving authentication - * @return string|array Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. - * - * @access public - */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, - $accept = false, $channel = false) - { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - if ($callback) { - call_user_func($callback, 'setup', array(&$ui)); - } - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); - } - - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); - } - - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; - - if (isset($this)) { - $config = &$this->config; - } else { - $config = &PEAR_Config::singleton(); - } - - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($config->get('http_proxy') && - $proxy = parse_url($config->get('http_proxy'))) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - - if ($callback) { - call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); - } - } - - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; - } - - $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; - - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, - $errno, $errstr)); - } - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); - } - - if ($lastmodified === false || $lastmodified) { - $request = "GET $url HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $url HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } - } else { - $network_host = $host; - if (isset($info['scheme']) && $info['scheme'] == 'https') { - $network_host = 'ssl://' . $host; - } - - $fp = @fsockopen($network_host, $port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($host, $port, - $errno, $errstr)); - } - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); - } - - if ($lastmodified === false || $lastmodified) { - $request = "GET $path HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $path HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } - } - - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; - } - - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; - } - } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); - } - - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; - - if (isset($this)) { // only pass in authentication for non-static calls - $username = $config->get('username', null, $channel); - $password = $config->get('password', null, $channel); - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; - } - } - - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; - } - - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; - } - - $request .= "Connection: close\r\n"; - $request .= "\r\n"; - fwrite($fp, $request); - $headers = array(); - $reply = 0; - while (trim($line = fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; - } - - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); - } - } - } - - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); - } - - if ($wasredirect > 4) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); - } - - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], - $ui, $save_dir, $callback, $lastmodified, $accept); - } - - if (isset($headers['content-disposition']) && - preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { - $save_as = basename($matches[1]); - } else { - $save_as = basename($url); - } - - if ($callback) { - $tmp = call_user_func($callback, 'saveas', $save_as); - if ($tmp) { - $save_as = $tmp; - } - } - - $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; - if (!$wp = @fopen($dest_file, 'wb')) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); - } - return PEAR::raiseError("could not open $dest_file for writing"); - } - - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - - $bytes = 0; - if ($callback) { - call_user_func($callback, 'start', array(basename($dest_file), $length)); - } - - while ($data = fread($fp, 1024)) { - $bytes += strlen($data); - if ($callback) { - call_user_func($callback, 'bytesread', $bytes); - } - if (!@fwrite($wp, $data)) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); - } - return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); - } - } - - fclose($fp); - fclose($wp); - if ($callback) { - call_user_func($callback, 'done', $bytes); - } - - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); - } - - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; - } else { - $lastmodified = $headers['last-modified']; - } - } - return array($dest_file, $lastmodified, $headers); - } - return $dest_file; - } -} -// }}} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Package.php 287560 2009-08-21 22:36:18Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Error code when parameter initialization fails because no releases - * exist within preferred_state, but releases do exist - */ -define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); -/** - * Error code when parameter initialization fails because no releases - * exist that will work with the existing PHP version - */ -define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); - -/** - * Coordinates download parameters and manages their dependencies - * prior to downloading them. - * - * Input can come from three sources: - * - * - local files (archives or package.xml) - * - remote files (downloadable urls) - * - abstract package names - * - * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires - * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the - * format returned of dependencies is slightly different from that used in package.xml. - * - * This class hides the differences between these elements, and makes automatic - * dependency resolution a piece of cake. It also manages conflicts when - * two classes depend on incompatible dependencies, or differing versions of the same - * package dependency. In addition, download will not be attempted if the php version is - * not supported, PEAR installer version is not supported, or non-PECL extensions are not - * installed. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Downloader_Package -{ - /** - * @var PEAR_Downloader - */ - var $_downloader; - /** - * @var PEAR_Config - */ - var $_config; - /** - * @var PEAR_Registry - */ - var $_registry; - /** - * Used to implement packagingroot properly - * @var PEAR_Registry - */ - var $_installRegistry; - /** - * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 - */ - var $_packagefile; - /** - * @var array - */ - var $_parsedname; - /** - * @var array - */ - var $_downloadURL; - /** - * @var array - */ - var $_downloadDeps = array(); - /** - * @var boolean - */ - var $_valid = false; - /** - * @var boolean - */ - var $_analyzed = false; - /** - * if this or a parent package was invoked with Package-state, this is set to the - * state variable. - * - * This allows temporary reassignment of preferred_state for a parent package and all of - * its dependencies. - * @var string|false - */ - var $_explicitState = false; - /** - * If this package is invoked with Package#group, this variable will be true - */ - var $_explicitGroup = false; - /** - * Package type local|url - * @var string - */ - var $_type; - /** - * Contents of package.xml, if downloaded from a remote channel - * @var string|false - * @access private - */ - var $_rawpackagefile; - /** - * @var boolean - * @access private - */ - var $_validated = false; - - /** - * @param PEAR_Downloader - */ - function PEAR_Downloader_Package(&$downloader) - { - $this->_downloader = &$downloader; - $this->_config = &$this->_downloader->config; - $this->_registry = &$this->_config->getRegistry(); - $options = $downloader->getOptions(); - if (isset($options['packagingroot'])) { - $this->_config->setInstallRoot($options['packagingroot']); - $this->_installRegistry = &$this->_config->getRegistry(); - $this->_config->setInstallRoot(false); - } else { - $this->_installRegistry = &$this->_registry; - } - $this->_valid = $this->_analyzed = false; - } - - /** - * Parse the input and determine whether this is a local file, a remote uri, or an - * abstract package name. - * - * This is the heart of the PEAR_Downloader_Package(), and is used in - * {@link PEAR_Downloader::download()} - * @param string - * @return bool|PEAR_Error - */ - function initialize($param) - { - $origErr = $this->_fromFile($param); - if ($this->_valid) { - return true; - } - - $options = $this->_downloader->getOptions(); - if (isset($options['offline'])) { - if (PEAR::isError($origErr) && !isset($options['soft'])) { - foreach ($origErr->getUserInfo() as $userInfo) { - if (isset($userInfo['message'])) { - $this->_downloader->log(0, $userInfo['message']); - } - } - - $this->_downloader->log(0, $origErr->getMessage()); - } - - return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); - } - - $err = $this->_fromUrl($param); - if (PEAR::isError($err) || !$this->_valid) { - if ($this->_type == 'url') { - if (PEAR::isError($err) && !isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } - - return PEAR::raiseError("Invalid or missing remote package file"); - } - - $err = $this->_fromString($param); - if (PEAR::isError($err) || !$this->_valid) { - if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { - return false; // instruct the downloader to silently skip - } - - if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) { - if (is_array($origErr->getUserInfo())) { - foreach ($origErr->getUserInfo() as $err) { - if (is_array($err)) { - $err = $err['message']; - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, $err); - } - } - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, $origErr->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param, true); - } - - if (!isset($options['soft'])) { - $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); - } - - // Passing no message back - already logged above - return PEAR::raiseError(); - } - - if (PEAR::isError($err) && !isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param, true); - } - - if (!isset($options['soft'])) { - $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); - } - - // Passing no message back - already logged above - return PEAR::raiseError(); - } - } - - return true; - } - - /** - * Retrieve any non-local packages - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error - */ - function &download() - { - if (isset($this->_packagefile)) { - return $this->_packagefile; - } - - if (isset($this->_downloadURL['url'])) { - $this->_isvalid = false; - $info = $this->getParsedPackage(); - foreach ($info as $i => $p) { - $info[$i] = strtolower($p); - } - - $err = $this->_fromUrl($this->_downloadURL['url'], - $this->_registry->parsedPackageNameToString($this->_parsedname, true)); - $newinfo = $this->getParsedPackage(); - foreach ($newinfo as $i => $p) { - $newinfo[$i] = strtolower($p); - } - - if ($info != $newinfo) { - do { - if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') { - $info['channel'] = 'pear.php.net'; - if ($info == $newinfo) { - // skip the channel check if a pecl package says it's a PEAR package - break; - } - } - if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') { - $info['channel'] = 'pecl.php.net'; - if ($info == $newinfo) { - // skip the channel check if a pecl package says it's a PEAR package - break; - } - } - - return PEAR::raiseError('CRITICAL ERROR: We are ' . - $this->_registry->parsedPackageNameToString($info) . ', but the file ' . - 'downloaded claims to be ' . - $this->_registry->parsedPackageNameToString($this->getParsedPackage())); - } while (false); - } - - if (PEAR::isError($err) || !$this->_valid) { - return $err; - } - } - - $this->_type = 'local'; - return $this->_packagefile; - } - - function &getPackageFile() - { - return $this->_packagefile; - } - - function &getDownloader() - { - return $this->_downloader; - } - - function getType() - { - return $this->_type; - } - - /** - * Like {@link initialize()}, but operates on a dependency - */ - function fromDepURL($dep) - { - $this->_downloadURL = $dep; - if (isset($dep['uri'])) { - $options = $this->_downloader->getOptions(); - if (!extension_loaded("zlib") || isset($options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->_fromUrl($dep['uri'] . $ext); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } - - return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . - 'cannot download'); - } - } else { - $this->_parsedname = - array( - 'package' => $dep['info']->getPackage(), - 'channel' => $dep['info']->getChannel(), - 'version' => $dep['version'] - ); - if (!isset($dep['nodefault'])) { - $this->_parsedname['group'] = 'default'; // download the default dependency group - $this->_explicitGroup = false; - } - - $this->_rawpackagefile = $dep['raw']; - } - } - - function detectDependencies($params) - { - $options = $this->_downloader->getOptions(); - if (isset($options['downloadonly'])) { - return; - } - - if (isset($options['offline'])) { - $this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); - return; - } - - $pname = $this->getParsedPackage(); - if (!$pname) { - return; - } - - $deps = $this->getDeps(); - if (!$deps) { - return; - } - - if (isset($deps['required'])) { // package.xml 2.0 - return $this->_detect2($deps, $pname, $options, $params); - } - - return $this->_detect1($deps, $pname, $options, $params); - } - - function setValidated() - { - $this->_validated = true; - } - - function alreadyValidated() - { - return $this->_validated; - } - - /** - * Remove packages to be downloaded that are already installed - * @param array of PEAR_Downloader_Package objects - * @static - */ - function removeInstalled(&$params) - { - if (!isset($params[0])) { - return; - } - - $options = $params[0]->_downloader->getOptions(); - if (!isset($options['downloadonly'])) { - foreach ($params as $i => $param) { - $package = $param->getPackage(); - $channel = $param->getChannel(); - // remove self if already installed with this version - // this does not need any pecl magic - we only remove exact matches - if ($param->_installRegistry->packageExists($package, $channel)) { - $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel); - if (version_compare($packageVersion, $param->getVersion(), '==')) { - if (!isset($options['force'])) { - $info = $param->getParsedPackage(); - unset($info['version']); - unset($info['state']); - if (!isset($options['soft'])) { - $param->_downloader->log(1, 'Skipping package "' . - $param->getShortName() . - '", already installed as version ' . $packageVersion); - } - $params[$i] = false; - } - } elseif (!isset($options['force']) && !isset($options['upgrade']) && - !isset($options['soft'])) { - $info = $param->getParsedPackage(); - $param->_downloader->log(1, 'Skipping package "' . - $param->getShortName() . - '", already installed as version ' . $packageVersion); - $params[$i] = false; - } - } - } - } - - PEAR_Downloader_Package::removeDuplicates($params); - } - - function _detect2($deps, $pname, $options, $params) - { - $this->_downloadDeps = array(); - $groupnotfound = false; - foreach (array('package', 'subpackage') as $packagetype) { - // get required dependency group - if (isset($deps['required'][$packagetype])) { - if (isset($deps['required'][$packagetype][0])) { - foreach ($deps['required'][$packagetype] as $dep) { - if (isset($dep['conflicts'])) { - // skip any package that this package conflicts with - continue; - } - $ret = $this->_detect2Dep($dep, $pname, 'required', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } else { - $dep = $deps['required'][$packagetype]; - if (!isset($dep['conflicts'])) { - // skip any package that this package conflicts with - $ret = $this->_detect2Dep($dep, $pname, 'required', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } - } - - // get optional dependency group, if any - if (isset($deps['optional'][$packagetype])) { - $skipnames = array(); - if (!isset($deps['optional'][$packagetype][0])) { - $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); - } - - foreach ($deps['optional'][$packagetype] as $dep) { - $skip = false; - if (!isset($options['alldeps'])) { - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->_registry->parsedPackageNameToString($this->getParsedPackage(), - true) . '" optional dependency "' . - $this->_registry->parsedPackageNameToString(array('package' => - $dep['name'], 'channel' => 'pear.php.net'), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); - $skip = true; - unset($dep['package']); - } - - $ret = $this->_detect2Dep($dep, $pname, 'optional', $params); - if (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - - if (!$ret) { - $dep['package'] = $dep['name']; - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - } - - if (!$skip && is_array($ret)) { - $this->_downloadDeps[] = $ret; - } - } - - if (count($skipnames)) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'Did not download optional dependencies: ' . - implode(', ', $skipnames) . - ', use --alldeps to download automatically'); - } - } - } - - // get requested dependency group, if any - $groupname = $this->getGroup(); - $explicit = $this->_explicitGroup; - if (!$groupname) { - if (!$this->canDefault()) { - continue; - } - - $groupname = 'default'; // try the default dependency group - } - - if ($groupnotfound) { - continue; - } - - if (isset($deps['group'])) { - if (isset($deps['group']['attribs'])) { - if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { - $group = $deps['group']; - } elseif ($explicit) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Warning: package "' . - $this->_registry->parsedPackageNameToString($pname, true) . - '" has no dependency ' . 'group named "' . $groupname . '"'); - } - - $groupnotfound = true; - continue; - } - } else { - $found = false; - foreach ($deps['group'] as $group) { - if (strtolower($group['attribs']['name']) == strtolower($groupname)) { - $found = true; - break; - } - } - - if (!$found) { - if ($explicit) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Warning: package "' . - $this->_registry->parsedPackageNameToString($pname, true) . - '" has no dependency ' . 'group named "' . $groupname . '"'); - } - } - - $groupnotfound = true; - continue; - } - } - } - - if (isset($group) && isset($group[$packagetype])) { - if (isset($group[$packagetype][0])) { - foreach ($group[$packagetype] as $dep) { - $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . - $group['attribs']['name'] . '"', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } else { - $ret = $this->_detect2Dep($group[$packagetype], $pname, - 'dependency group "' . - $group['attribs']['name'] . '"', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } - } - } - - function _detect2Dep($dep, $pname, $group, $params) - { - if (isset($dep['conflicts'])) { - return true; - } - - $options = $this->_downloader->getOptions(); - if (isset($dep['uri'])) { - return array('uri' => $dep['uri'], 'dep' => $dep);; - } - - $testdep = $dep; - $testdep['package'] = $dep['name']; - if (PEAR_Downloader_Package::willDownload($testdep, $params)) { - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", will be installed'); - } - return false; - } - - $options = $this->_downloader->getOptions(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if ($this->_explicitState) { - $pname['state'] = $this->_explicitState; - } - - $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); - if (PEAR::isError($url)) { - PEAR::popErrorHandling(); - return $url; - } - - $dep['package'] = $dep['name']; - $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && - !isset($options['alldeps']), true); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - - return false; - } - - // check to see if a dep is already installed and is the same or newer - if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { - $oper = 'has'; - } else { - $oper = 'gt'; - } - - // do not try to move this before getDepPackageDownloadURL - // we can't determine whether upgrade is necessary until we know what - // version would be downloaded - if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']); - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '" version ' . $url['version'] . ', already installed as version ' . - $version); - } - - return false; - } - - if (isset($dep['nodefault'])) { - $ret['nodefault'] = true; - } - - return $ret; - } - - function _detect1($deps, $pname, $options, $params) - { - $this->_downloadDeps = array(); - $skipnames = array(); - foreach ($deps as $dep) { - $nodownload = false; - if (isset ($dep['type']) && $dep['type'] === 'pkg') { - $dep['channel'] = 'pear.php.net'; - $dep['package'] = $dep['name']; - switch ($dep['rel']) { - case 'not' : - continue 2; - case 'ge' : - case 'eq' : - case 'gt' : - case 'has' : - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - if (PEAR_Downloader_Package::willDownload($dep, $params)) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group - . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", will be installed'); - continue 2; - } - $fakedp = new PEAR_PackageFile_v1; - $fakedp->setPackage($dep['name']); - // skip internet check if we are not upgrading (bug #5810) - if (!isset($options['upgrade']) && $this->isInstalled( - $fakedp, $dep['rel'])) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group - . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", is already installed'); - continue 2; - } - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if ($this->_explicitState) { - $pname['state'] = $this->_explicitState; - } - - $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); - $chan = 'pear.php.net'; - if (PEAR::isError($url)) { - // check to see if this is a pecl package that has jumped - // from pear.php.net to pecl.php.net channel - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - - $newdep = PEAR_Dependency2::normalizeDep($dep); - $newdep = $newdep[0]; - $newdep['channel'] = 'pecl.php.net'; - $chan = 'pecl.php.net'; - $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); - $obj = &$this->_installRegistry->getPackage($dep['name']); - if (PEAR::isError($url)) { - PEAR::popErrorHandling(); - if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . - ': Skipping ' . $group . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", already installed as version ' . $obj->getVersion()); - } - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - continue; - } else { - if (isset($dep['optional']) && $dep['optional'] == 'yes') { - $this->_downloader->log(2, $this->getShortName() . - ': Skipping optional dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", no releases exist'); - continue; - } else { - return $url; - } - } - } - } - - PEAR::popErrorHandling(); - if (!isset($options['alldeps'])) { - if (isset($dep['optional']) && $dep['optional'] == 'yes') { - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->getShortName() . - '" optional dependency "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true); - $nodownload = true; - } - } - - if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { - if (!isset($dep['optional']) || $dep['optional'] == 'no') { - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->getShortName() . - '" required dependency "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true); - $nodownload = true; - } - } - - // check to see if a dep is already installed - // do not try to move this before getDepPackageDownloadURL - // we can't determine whether upgrade is necessary until we know what - // version would be downloaded - if (!isset($options['force']) && $this->isInstalled( - $url, $dep['rel'])) { - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - $dep['package'] = $dep['name']; - if (isset($newdep)) { - $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']); - } else { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); - } - - $dep['version'] = $url['version']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", already installed as version ' . $version); - } - - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - - continue; - } - - if ($nodownload) { - continue; - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (isset($newdep)) { - $dep = $newdep; - } - - $dep['package'] = $dep['name']; - $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, - isset($dep['optional']) && $dep['optional'] == 'yes' && - !isset($options['alldeps']), true); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - continue; - } - - $this->_downloadDeps[] = $ret; - } - } - - if (count($skipnames)) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'Did not download dependencies: ' . - implode(', ', $skipnames) . - ', use --alldeps or --onlyreqdeps to download automatically'); - } - } - } - - function setDownloadURL($pkg) - { - $this->_downloadURL = $pkg; - } - - /** - * Set the package.xml object for this downloaded package - * - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg - */ - function setPackageFile(&$pkg) - { - $this->_packagefile = &$pkg; - } - - function getShortName() - { - return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), - 'package' => $this->getPackage()), true); - } - - function getParsedPackage() - { - if (isset($this->_packagefile) || isset($this->_parsedname)) { - return array('channel' => $this->getChannel(), - 'package' => $this->getPackage(), - 'version' => $this->getVersion()); - } - - return false; - } - - function getDownloadURL() - { - return $this->_downloadURL; - } - - function canDefault() - { - if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) { - return false; - } - - return true; - } - - function getPackage() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackage(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackage(); - } - - return false; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function isSubpackage(&$pf) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isSubpackage($pf); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->isSubpackage($pf); - } - - return false; - } - - function getPackageType() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackageType(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackageType(); - } - - return false; - } - - function isBundle() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackageType() == 'bundle'; - } - - return false; - } - - function getPackageXmlVersion() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackagexmlVersion(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackagexmlVersion(); - } - - return '1.0'; - } - - function getChannel() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getChannel(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getChannel(); - } - - return false; - } - - function getURI() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getURI(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getURI(); - } - - return false; - } - - function getVersion() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getVersion(); - } elseif (isset($this->_downloadURL['version'])) { - return $this->_downloadURL['version']; - } - - return false; - } - - function isCompatible($pf) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isCompatible($pf); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->isCompatible($pf); - } - - return true; - } - - function setGroup($group) - { - $this->_parsedname['group'] = $group; - } - - function getGroup() - { - if (isset($this->_parsedname['group'])) { - return $this->_parsedname['group']; - } - - return ''; - } - - function isExtension($name) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isExtension($name); - } elseif (isset($this->_downloadURL['info'])) { - if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { - return $this->_downloadURL['info']->getProvidesExtension() == $name; - } - - return false; - } - - return false; - } - - function getDeps() - { - if (isset($this->_packagefile)) { - $ver = $this->_packagefile->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - return $this->_packagefile->getDeps(true); - } - - return $this->_packagefile->getDeps(); - } elseif (isset($this->_downloadURL['info'])) { - $ver = $this->_downloadURL['info']->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - return $this->_downloadURL['info']->getDeps(true); - } - - return $this->_downloadURL['info']->getDeps(); - } - - return array(); - } - - /** - * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency - * returned from getDepDownloadURL() - */ - function isEqual($param) - { - if (is_object($param)) { - $channel = $param->getChannel(); - $package = $param->getPackage(); - if ($param->getURI()) { - $param = array( - 'channel' => $param->getChannel(), - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - 'uri' => $param->getURI(), - ); - } else { - $param = array( - 'channel' => $param->getChannel(), - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - ); - } - } else { - if (isset($param['uri'])) { - if ($this->getChannel() != '__uri') { - return false; - } - return $param['uri'] == $this->getURI(); - } - - $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage(); - $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel(); - if (isset($param['rel'])) { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - - $newdep = PEAR_Dependency2::normalizeDep($param); - $newdep = $newdep[0]; - } elseif (isset($param['min'])) { - $newdep = $param; - } - } - - if (isset($newdep)) { - if (!isset($newdep['min'])) { - $newdep['min'] = '0'; - } - - if (!isset($newdep['max'])) { - $newdep['max'] = '100000000000000000000'; - } - - // use magic to support pecl packages suddenly jumping to the pecl channel - // we need to support both dependency possibilities - if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { - if ($package == $this->getPackage()) { - $channel = 'pecl.php.net'; - } - } - if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { - if ($package == $this->getPackage()) { - $channel = 'pear.php.net'; - } - } - - return (strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel() && - version_compare($newdep['min'], $this->getVersion(), '<=') && - version_compare($newdep['max'], $this->getVersion(), '>=')); - } - - // use magic to support pecl packages suddenly jumping to the pecl channel - if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { - if (strtolower($package) == strtolower($this->getPackage())) { - $channel = 'pear.php.net'; - } - } - - if (isset($param['version'])) { - return (strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel() && - $param['version'] == $this->getVersion()); - } - - return strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel(); - } - - function isInstalled($dep, $oper = '==') - { - if (!$dep) { - return false; - } - - if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { - return false; - } - - if (is_object($dep)) { - $package = $dep->getPackage(); - $channel = $dep->getChannel(); - if ($dep->getURI()) { - $dep = array( - 'uri' => $dep->getURI(), - 'version' => $dep->getVersion(), - ); - } else { - $dep = array( - 'version' => $dep->getVersion(), - ); - } - } else { - if (isset($dep['uri'])) { - $channel = '__uri'; - $package = $dep['dep']['name']; - } else { - $channel = $dep['info']->getChannel(); - $package = $dep['info']->getPackage(); - } - } - - $options = $this->_downloader->getOptions(); - $test = $this->_installRegistry->packageExists($package, $channel); - if (!$test && $channel == 'pecl.php.net') { - // do magic to allow upgrading from old pecl packages to new ones - $test = $this->_installRegistry->packageExists($package, 'pear.php.net'); - $channel = 'pear.php.net'; - } - - if ($test) { - if (isset($dep['uri'])) { - if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { - return true; - } - } - - if (isset($options['upgrade'])) { - $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel); - if (version_compare($packageVersion, $dep['version'], '>=')) { - return true; - } - - return false; - } - - return true; - } - - return false; - } - - /** - * Detect duplicate package names with differing versions - * - * If a user requests to install Date 1.4.6 and Date 1.4.7, - * for instance, this is a logic error. This method - * detects this situation. - * - * @param array $params array of PEAR_Downloader_Package objects - * @param array $errorparams empty array - * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts - */ - function detectStupidDuplicates($params, &$errorparams) - { - $existing = array(); - foreach ($params as $i => $param) { - $package = $param->getPackage(); - $channel = $param->getChannel(); - $group = $param->getGroup(); - if (!isset($existing[$channel . '/' . $package])) { - $existing[$channel . '/' . $package] = array(); - } - - if (!isset($existing[$channel . '/' . $package][$group])) { - $existing[$channel . '/' . $package][$group] = array(); - } - - $existing[$channel . '/' . $package][$group][] = $i; - } - - $indices = array(); - foreach ($existing as $package => $groups) { - foreach ($groups as $group => $dupes) { - if (count($dupes) > 1) { - $indices = $indices + $dupes; - } - } - } - - $indices = array_unique($indices); - foreach ($indices as $index) { - $errorparams[] = $params[$index]; - } - - return count($errorparams); - } - - /** - * @param array - * @param bool ignore install groups - for final removal of dupe packages - * @static - */ - function removeDuplicates(&$params, $ignoreGroups = false) - { - $pnames = array(); - foreach ($params as $i => $param) { - if (!$param) { - continue; - } - - if ($param->getPackage()) { - $group = $ignoreGroups ? '' : $param->getGroup(); - $pnames[$i] = $param->getChannel() . '/' . - $param->getPackage() . '-' . $param->getVersion() . '#' . $group; - } - } - - $pnames = array_unique($pnames); - $unset = array_diff(array_keys($params), array_keys($pnames)); - $testp = array_flip($pnames); - foreach ($params as $i => $param) { - if (!$param) { - $unset[] = $i; - continue; - } - - if (!is_a($param, 'PEAR_Downloader_Package')) { - $unset[] = $i; - continue; - } - - $group = $ignoreGroups ? '' : $param->getGroup(); - if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . - $param->getVersion() . '#' . $group])) { - $unset[] = $i; - } - } - - foreach ($unset as $i) { - unset($params[$i]); - } - - $ret = array(); - foreach ($params as $i => $param) { - $ret[] = &$params[$i]; - } - - $params = array(); - foreach ($ret as $i => $param) { - $params[] = &$ret[$i]; - } - } - - function explicitState() - { - return $this->_explicitState; - } - - function setExplicitState($s) - { - $this->_explicitState = $s; - } - - /** - * @static - */ - function mergeDependencies(&$params) - { - $bundles = $newparams = array(); - foreach ($params as $i => $param) { - if (!$param->isBundle()) { - continue; - } - - $bundles[] = $i; - $pf = &$param->getPackageFile(); - $newdeps = array(); - $contents = $pf->getBundledPackages(); - if (!is_array($contents)) { - $contents = array($contents); - } - - foreach ($contents as $file) { - $filecontents = $pf->getFileContents($file); - $dl = &$param->getDownloader(); - $options = $dl->getOptions(); - if (PEAR::isError($dir = $dl->getDownloadDir())) { - return $dir; - } - - $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); - if (!$fp) { - continue; - } - - fwrite($fp, $filecontents, strlen($filecontents)); - fclose($fp); - if ($s = $params[$i]->explicitState()) { - $obj->setExplicitState($s); - } - - $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($dir = $dl->getDownloadDir())) { - PEAR::popErrorHandling(); - return $dir; - } - - $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file); - PEAR::popErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $dl->log(0, $e->getMessage()); - } - continue; - } - - $j = &$obj; - if (!PEAR_Downloader_Package::willDownload($j, - array_merge($params, $newparams)) && !$param->isInstalled($j)) { - $newparams[] = &$j; - } - } - } - - foreach ($bundles as $i) { - unset($params[$i]); // remove bundles - only their contents matter for installation - } - - PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices - if (count($newparams)) { // add in bundled packages for install - foreach ($newparams as $i => $unused) { - $params[] = &$newparams[$i]; - } - $newparams = array(); - } - - foreach ($params as $i => $param) { - $newdeps = array(); - foreach ($param->_downloadDeps as $dep) { - $merge = array_merge($params, $newparams); - if (!PEAR_Downloader_Package::willDownload($dep, $merge) - && !$param->isInstalled($dep) - ) { - $newdeps[] = $dep; - } else { - //var_dump($dep); - // detect versioning conflicts here - } - } - - // convert the dependencies into PEAR_Downloader_Package objects for the next time around - $params[$i]->_downloadDeps = array(); - foreach ($newdeps as $dep) { - $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); - if ($s = $params[$i]->explicitState()) { - $obj->setExplicitState($s); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $e = $obj->fromDepURL($dep); - PEAR::popErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $obj->_downloader->log(0, $e->getMessage()); - } - continue; - } - - $e = $obj->detectDependencies($params); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $obj->_downloader->log(0, $e->getMessage()); - } - } - - $j = &$obj; - $newparams[] = &$j; - } - } - - if (count($newparams)) { - foreach ($newparams as $i => $unused) { - $params[] = &$newparams[$i]; - } - return true; - } - - return false; - } - - - /** - * @static - */ - function willDownload($param, $params) - { - if (!is_array($params)) { - return false; - } - - foreach ($params as $obj) { - if ($obj->isEqual($param)) { - return true; - } - } - - return false; - } - - /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string - */ - function &getPackagefileObject(&$c, $d, $t = false) - { - $a = &new PEAR_PackageFile($c, $d, $t); - return $a; - } - - - /** - * This will retrieve from a local file if possible, and parse out - * a group name as well. The original parameter will be modified to reflect this. - * @param string|array can be a parsed package name as well - * @access private - */ - function _fromFile(&$param) - { - $saveparam = $param; - if (is_string($param)) { - if (!@file_exists($param)) { - $test = explode('#', $param); - $group = array_pop($test); - if (@file_exists(implode('#', $test))) { - $this->setGroup($group); - $param = implode('#', $test); - $this->_explicitGroup = true; - } - } - - if (@is_file($param)) { - $this->_type = 'local'; - $options = $this->_downloader->getOptions(); - if (isset($options['downloadonly'])) { - $pkg = &$this->getPackagefileObject($this->_config, - $this->_downloader->_debug); - } else { - if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { - return $dir; - } - $pkg = &$this->getPackagefileObject($this->_config, - $this->_downloader->_debug, $dir); - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); - PEAR::popErrorHandling(); - if (PEAR::isError($pf)) { - $this->_valid = false; - $param = $saveparam; - return $pf; - } - $this->_packagefile = &$pf; - if (!$this->getGroup()) { - $this->setGroup('default'); // install the default dependency group - } - return $this->_valid = true; - } - } - $param = $saveparam; - return $this->_valid = false; - } - - function _fromUrl($param, $saveparam = '') - { - if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) { - $options = $this->_downloader->getOptions(); - $this->_type = 'url'; - $callback = $this->_downloader->ui ? - array(&$this->_downloader, '_downloadCallback') : null; - $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { - $this->_downloader->popErrorHandling(); - return $dir; - } - - $this->_downloader->log(3, 'Downloading "' . $param . '"'); - $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, - $dir, $callback, null, false, $this->getChannel()); - $this->_downloader->popErrorHandling(); - if (PEAR::isError($file)) { - if (!empty($saveparam)) { - $saveparam = ", cannot download \"$saveparam\""; - } - $err = PEAR::raiseError('Could not download from "' . $param . - '"' . $saveparam . ' (' . $file->getMessage() . ')'); - return $err; - } - - if ($this->_rawpackagefile) { - require_once 'phar://go-pear.phar/' . 'Archive/Tar.php'; - $tar = &new Archive_Tar($file); - $packagexml = $tar->extractInString('package2.xml'); - if (!$packagexml) { - $packagexml = $tar->extractInString('package.xml'); - } - - if (str_replace(array("\n", "\r"), array('',''), $packagexml) != - str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { - if ($this->getChannel() != 'pear.php.net') { - return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . - 'not match value returned from xml-rpc'); - } - - // be more lax for the existing PEAR packages that have not-ok - // characters in their package.xml - $this->_downloader->log(0, 'CRITICAL WARNING: The "' . - $this->getPackage() . '" package has invalid characters in its ' . - 'package.xml. The next version of PEAR may not be able to install ' . - 'this package for security reasons. Please open a bug report at ' . - 'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); - } - } - - // whew, download worked! - if (isset($options['downloadonly'])) { - $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); - } else { - $dir = $this->_downloader->getDownloadDir(); - if (PEAR::isError($dir)) { - return $dir; - } - $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug, $dir); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); - PEAR::popErrorHandling(); - if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $err) { - if (is_array($err)) { - $err = $err['message']; - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, "Validation Error: $err"); - } - } - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pf->getMessage()); - } - - ///FIXME need to pass back some error code that we can use to match with to cancel all further operations - /// At least stop all deps of this package from being installed - $out = $saveparam ? $saveparam : $param; - $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive'); - $this->_valid = false; - return $err; - } - - $this->_packagefile = &$pf; - $this->setGroup('default'); // install the default dependency group - return $this->_valid = true; - } - - return $this->_valid = false; - } - - /** - * - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',]) - * or a string of format [channame/]pname[-version|-state] - */ - function _fromString($param) - { - $options = $this->_downloader->getOptions(); - $channel = $this->_config->get('default_channel'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pname = $this->_registry->parsePackageName($param, $channel); - PEAR::popErrorHandling(); - if (PEAR::isError($pname)) { - if ($pname->getCode() == 'invalid') { - $this->_valid = false; - return false; - } - - if ($pname->getCode() == 'channel') { - $parsed = $pname->getUserInfo(); - if ($this->_downloader->discover($parsed['channel'])) { - if ($this->_config->get('auto_discover')) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pname = $this->_registry->parsePackageName($param, $channel); - PEAR::popErrorHandling(); - } else { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Channel "' . $parsed['channel'] . - '" is not initialized, use ' . - '"pear channel-discover ' . $parsed['channel'] . '" to initialize' . - 'or pear config-set auto_discover 1'); - } - } - } - - if (PEAR::isError($pname)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pname->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param); - } - - $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); - $this->_valid = false; - return $err; - } - } else { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pname->getMessage()); - } - - $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); - $this->_valid = false; - return $err; - } - } - - if (!isset($this->_type)) { - $this->_type = 'rest'; - } - - $this->_parsedname = $pname; - $this->_explicitState = isset($pname['state']) ? $pname['state'] : false; - $this->_explicitGroup = isset($pname['group']) ? true : false; - - $info = $this->_downloader->_getPackageDownloadUrl($pname); - if (PEAR::isError($info)) { - if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { - // try pecl - $pname['channel'] = 'pecl.php.net'; - if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { - if (!PEAR::isError($test)) { - $info = PEAR::raiseError($info->getMessage() . ' - package ' . - $this->_registry->parsedPackageNameToString($pname, true) . - ' can be installed with "pecl install ' . $pname['package'] . - '"'); - } else { - $pname['channel'] = 'pear.php.net'; - } - } else { - $pname['channel'] = 'pear.php.net'; - } - } - - return $info; - } - - $this->_rawpackagefile = $info['raw']; - $ret = $this->_analyzeDownloadURL($info, $param, $pname); - if (PEAR::isError($ret)) { - return $ret; - } - - if ($ret) { - $this->_downloadURL = $ret; - return $this->_valid = (bool) $ret; - } - } - - /** - * @param array output of package.getDownloadURL - * @param string|array|object information for detecting packages to be downloaded, and - * for errors - * @param array name information of the package - * @param array|null packages to be downloaded - * @param bool is this an optional dependency? - * @param bool is this any kind of dependency? - * @access private - */ - function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, - $isdependency = false) - { - if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { - return false; - } - - if ($info === false) { - $saveparam = !is_string($param) ? ", cannot download \"$param\"" : ''; - - // no releases exist - return PEAR::raiseError('No releases for package "' . - $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); - } - - if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { - $err = false; - if ($pname['channel'] == 'pecl.php.net') { - if ($info['info']->getChannel() != 'pear.php.net') { - $err = true; - } - } elseif ($info['info']->getChannel() == 'pecl.php.net') { - if ($pname['channel'] != 'pear.php.net') { - $err = true; - } - } else { - $err = true; - } - - if ($err) { - return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . - '" retrieved another channel\'s name for download! ("' . - $info['info']->getChannel() . '")'); - } - } - - $preferred_state = $this->_config->get('preferred_state'); - if (!isset($info['url'])) { - $package_version = $this->_registry->packageInfo($info['info']->getPackage(), - 'version', $info['info']->getChannel()); - if ($this->isInstalled($info)) { - if ($isdependency && version_compare($info['version'], $package_version, '<=')) { - // ignore bogus errors of "failed to download dependency" - // if it is already installed and the one that would be - // downloaded is older or the same version (Bug #7219) - return false; - } - } - - if ($info['version'] === $package_version) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' . - ' (' . $package_version . ') is the same as the locally installed one.'); - } - - return false; - } - - if (version_compare($info['version'], $package_version, '<=')) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . - ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); - } - - return false; - } - - $instead = ', will instead download version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '"'; - // releases exist, but we failed to get any - if (isset($this->_downloader->_options['force'])) { - if (isset($pname['version'])) { - $vs = ', version "' . $pname['version'] . '"'; - } elseif (isset($pname['state'])) { - $vs = ', stability "' . $pname['state'] . '"'; - } elseif ($param == 'dependency') { - if (!class_exists('PEAR_Common')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Common.php'; - } - - if (!in_array($info['info']->getState(), - PEAR_Common::betterStates($preferred_state, true))) { - if ($optional) { - // don't spit out confusing error message - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = ' within preferred state "' . $preferred_state . - '"'; - } else { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - - if ($optional) { - // don't spit out confusing error message - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = PEAR_Dependency2::_getExtraString($pname); - $instead = ''; - } - } else { - $vs = ' within preferred state "' . $preferred_state . '"'; - } - - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . $vs . $instead); - } - - // download the latest release - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } else { - if (isset($info['php']) && $info['php']) { - $err = PEAR::raiseError('Failed to download ' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], - 'package' => $pname['package']), - true) . - ', latest release is version ' . $info['php']['v'] . - ', but it requires PHP version "' . - $info['php']['m'] . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['php']['v'])) . '" to install', - PEAR_DOWNLOADER_PACKAGE_PHPVERSION); - return $err; - } - - // construct helpful error message - if (isset($pname['version'])) { - $vs = ', version "' . $pname['version'] . '"'; - } elseif (isset($pname['state'])) { - $vs = ', stability "' . $pname['state'] . '"'; - } elseif ($param == 'dependency') { - if (!class_exists('PEAR_Common')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Common.php'; - } - - if (!in_array($info['info']->getState(), - PEAR_Common::betterStates($preferred_state, true))) { - if ($optional) { - // don't spit out confusing error message, and don't die on - // optional dep failure! - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = ' within preferred state "' . $preferred_state . '"'; - } else { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - - if ($optional) { - // don't spit out confusing error message, and don't die on - // optional dep failure! - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = PEAR_Dependency2::_getExtraString($pname); - } - } else { - $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"'; - } - - $options = $this->_downloader->getOptions(); - // this is only set by the "download-all" command - if (isset($options['ignorepreferred_state'])) { - $err = PEAR::raiseError( - 'Failed to download ' . $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package']), - true) - . $vs . - ', latest release is version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['version'])) . '" to install', - PEAR_DOWNLOADER_PACKAGE_STATE); - return $err; - } - - // Checks if the user has a package installed already and checks the release against - // the state against the installed package, this allows upgrades for packages - // with lower stability than the preferred_state - $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']); - if (!$this->isInstalled($info) - || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true)) - ) { - $err = PEAR::raiseError( - 'Failed to download ' . $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package']), - true) - . $vs . - ', latest release is version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['version'])) . '" to install'); - return $err; - } - } - } - - if (isset($info['deprecated']) && $info['deprecated']) { - $this->_downloader->log(0, - 'WARNING: "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $info['info']->getChannel(), - 'package' => $info['info']->getPackage()), true) . - '" is deprecated in favor of "' . - $this->_registry->parsedPackageNameToString($info['deprecated'], true) . - '"'); - } - - return $info; - } -} - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ - -/** - * Singleton storage - * - * Format: - *
    - * array(
    - *  'package1' => PEAR_ErrorStack object,
    - *  'package2' => PEAR_ErrorStack object,
    - *  ...
    - * )
    - * 
    - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] - */ -$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); - -/** - * Global error callback (default) - * - * This is only used if set to non-false. * is the default callback for - * all packages, whereas specific packages may set a default callback - * for all instances, regardless of whether they are a singleton or not. - * - * To exclude non-singletons, only set the local callback for the singleton - * @see PEAR_ErrorStack::setDefaultCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( - '*' => false, -); - -/** - * Global Log object (default) - * - * This is only used if set to non-false. Use to set a default log object for - * all stacks, regardless of instantiation order or location - * @see PEAR_ErrorStack::setDefaultLogger() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; - -/** - * Global Overriding Callback - * - * This callback will override any error callbacks that specific loggers have set. - * Use with EXTREME caution - * @see PEAR_ErrorStack::staticPushCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - -/**#@+ - * One of four possible return values from the error Callback - * @see PEAR_ErrorStack::_errorCallback() - */ -/** - * If this is returned, then the error will be both pushed onto the stack - * and logged. - */ -define('PEAR_ERRORSTACK_PUSHANDLOG', 1); -/** - * If this is returned, then the error will only be pushed onto the stack, - * and not logged. - */ -define('PEAR_ERRORSTACK_PUSH', 2); -/** - * If this is returned, then the error will only be logged, but not pushed - * onto the error stack. - */ -define('PEAR_ERRORSTACK_LOG', 3); -/** - * If this is returned, then the error is completely ignored. - */ -define('PEAR_ERRORSTACK_IGNORE', 4); -/** - * If this is returned, then the error is logged and die() is called. - */ -define('PEAR_ERRORSTACK_DIE', 5); -/**#@-*/ - -/** - * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in - * the singleton method. - */ -define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); - -/** - * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} - * that has no __toString() method - */ -define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); -/** - * Error Stack Implementation - * - * Usage: - * - * // global error stack - * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); - * // local error stack - * $local_stack = new PEAR_ErrorStack('MyPackage'); - * - * @author Greg Beaver - * @version 1.9.0 - * @package PEAR_ErrorStack - * @category Debugging - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ -class PEAR_ErrorStack { - /** - * Errors are stored in the order that they are pushed on the stack. - * @since 0.4alpha Errors are no longer organized by error level. - * This renders pop() nearly unusable, and levels could be more easily - * handled in a callback anyway - * @var array - * @access private - */ - var $_errors = array(); - - /** - * Storage of errors by level. - * - * Allows easy retrieval and deletion of only errors from a particular level - * @since PEAR 1.4.0dev - * @var array - * @access private - */ - var $_errorsByLevel = array(); - - /** - * Package name this error stack represents - * @var string - * @access protected - */ - var $_package; - - /** - * Determines whether a PEAR_Error is thrown upon every error addition - * @var boolean - * @access private - */ - var $_compat = false; - - /** - * If set to a valid callback, this will be used to generate the error - * message from the error code, otherwise the message passed in will be - * used - * @var false|string|array - * @access private - */ - var $_msgCallback = false; - - /** - * If set to a valid callback, this will be used to generate the error - * context for an error. For PHP-related errors, this will be a file - * and line number as retrieved from debug_backtrace(), but can be - * customized for other purposes. The error might actually be in a separate - * configuration file, or in a database query. - * @var false|string|array - * @access protected - */ - var $_contextCallback = false; - - /** - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one an PEAR_ERRORSTACK_* constant - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @var false|string|array - * @access protected - */ - var $_errorCallback = array(); - - /** - * PEAR::Log object for logging errors - * @var false|Log - * @access protected - */ - var $_logger = false; - - /** - * Error messages - designed to be overridden - * @var array - * @abstract - */ - var $_errorMsgs = array(); - - /** - * Set up a new error stack - * - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - */ - function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false) - { - $this->_package = $package; - $this->setMessageCallback($msgCallback); - $this->setContextCallback($contextCallback); - $this->_compat = $throwPEAR_Error; - } - - /** - * Return a single error stack for this package. - * - * Note that all parameters are ignored if the stack for package $package - * has already been instantiated - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - * @param string $stackClass class to instantiate - * @static - * @return PEAR_ErrorStack - */ - function &singleton($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') - { - if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - if (!class_exists($stackClass)) { - if (function_exists('debug_backtrace')) { - $trace = debug_backtrace(); - } - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, - 'exception', array('stackclass' => $stackClass), - 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', - false, $trace); - } - $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = - new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); - - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - - /** - * Internal error handler for PEAR_ErrorStack class - * - * Dies if the error is an exception (and would have died anyway) - * @access private - */ - function _handleError($err) - { - if ($err['level'] == 'exception') { - $message = $err['message']; - if (isset($_SERVER['REQUEST_URI'])) { - echo '
    '; - } else { - echo "\n"; - } - var_dump($err['context']); - die($message); - } - } - - /** - * Set up a PEAR::Log object for all error stacks that don't have one - * @param Log $log - * @static - */ - function setDefaultLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } elseif (is_callable($log)) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } - } - - /** - * Set up a PEAR::Log object for this error stack - * @param Log $log - */ - function setLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $this->_logger = &$log; - } elseif (is_callable($log)) { - $this->_logger = &$log; - } - } - - /** - * Set an error code => error message mapping callback - * - * This method sets the callback that can be used to generate error - * messages for any instance - * @param array|string Callback function/method - */ - function setMessageCallback($msgCallback) - { - if (!$msgCallback) { - $this->_msgCallback = array(&$this, 'getErrorMessage'); - } else { - if (is_callable($msgCallback)) { - $this->_msgCallback = $msgCallback; - } - } - } - - /** - * Get an error code => error message mapping callback - * - * This method returns the current callback that can be used to generate error - * messages - * @return array|string|false Callback function/method or false if none - */ - function getMessageCallback() - { - return $this->_msgCallback; - } - - /** - * Sets a default callback to be used by all error stacks - * - * This method sets the callback that can be used to generate error - * messages for a singleton - * @param array|string Callback function/method - * @param string Package name, or false for all packages - * @static - */ - function setDefaultCallback($callback = false, $package = false) - { - if (!is_callable($callback)) { - $callback = false; - } - $package = $package ? $package : '*'; - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; - } - - /** - * Set a callback that generates context information (location of error) for an error stack - * - * This method sets the callback that can be used to generate context - * information for an error. Passing in NULL will disable context generation - * and remove the expensive call to debug_backtrace() - * @param array|string|null Callback function/method - */ - function setContextCallback($contextCallback) - { - if ($contextCallback === null) { - return $this->_contextCallback = false; - } - if (!$contextCallback) { - $this->_contextCallback = array(&$this, 'getFileLine'); - } else { - if (is_callable($contextCallback)) { - $this->_contextCallback = $contextCallback; - } - } - } - - /** - * Set an error Callback - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one of the ERRORSTACK_* constants. - * - * This functionality can be used to emulate PEAR's pushErrorHandling, and - * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of - * the error stack or logging - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see popCallback() - * @param string|array $cb - */ - function pushCallback($cb) - { - array_push($this->_errorCallback, $cb); - } - - /** - * Remove a callback from the error callback stack - * @see pushCallback() - * @return array|string|false - */ - function popCallback() - { - if (!count($this->_errorCallback)) { - return false; - } - return array_pop($this->_errorCallback); - } - - /** - * Set a temporary overriding error callback for every package error stack - * - * Use this to temporarily disable all existing callbacks (can be used - * to emulate the @ operator, for instance) - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see staticPopCallback(), pushCallback() - * @param string|array $cb - * @static - */ - function staticPushCallback($cb) - { - array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); - } - - /** - * Remove a temporary overriding error callback - * @see staticPushCallback() - * @return array|string|false - * @static - */ - function staticPopCallback() - { - $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); - if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { - $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - } - return $ret; - } - - /** - * Add an error to the stack - * - * If the message generator exists, it is called with 2 parameters. - * - the current Error Stack object - * - an array that is in the same format as an error. Available indices - * are 'code', 'package', 'time', 'params', 'level', and 'context' - * - * Next, if the error should contain context information, this is - * handled by the context grabbing method. - * Finally, the error is pushed onto the proper error stack - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. If a PEAR_Error is returned, the userinfo - * property is set to the following array: - * - * - * array( - * 'code' => $code, - * 'params' => $params, - * 'package' => $this->_package, - * 'level' => $level, - * 'time' => time(), - * 'context' => $context, - * 'message' => $msg, - * //['repackage' => $err] repackaged error array/Exception class - * ); - * - * - * Normally, the previous array is returned. - */ - function push($code, $level = 'error', $params = array(), $msg = false, - $repackage = false, $backtrace = false) - { - $context = false; - // grab error context - if ($this->_contextCallback) { - if (!$backtrace) { - $backtrace = debug_backtrace(); - } - $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); - } - - // save error - $time = explode(' ', microtime()); - $time = $time[1] + $time[0]; - $err = array( - 'code' => $code, - 'params' => $params, - 'package' => $this->_package, - 'level' => $level, - 'time' => $time, - 'context' => $context, - 'message' => $msg, - ); - - if ($repackage) { - $err['repackage'] = $repackage; - } - - // set up the error message, if necessary - if ($this->_msgCallback) { - $msg = call_user_func_array($this->_msgCallback, - array(&$this, $err)); - $err['message'] = $msg; - } - $push = $log = true; - $die = false; - // try the overriding callback first - $callback = $this->staticPopCallback(); - if ($callback) { - $this->staticPushCallback($callback); - } - if (!is_callable($callback)) { - // try the local callback next - $callback = $this->popCallback(); - if (is_callable($callback)) { - $this->pushCallback($callback); - } else { - // try the default callback - $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; - } - } - if (is_callable($callback)) { - switch(call_user_func($callback, $err)){ - case PEAR_ERRORSTACK_IGNORE: - return $err; - break; - case PEAR_ERRORSTACK_PUSH: - $log = false; - break; - case PEAR_ERRORSTACK_LOG: - $push = false; - break; - case PEAR_ERRORSTACK_DIE: - $die = true; - break; - // anything else returned has the same effect as pushandlog - } - } - if ($push) { - array_unshift($this->_errors, $err); - if (!isset($this->_errorsByLevel[$err['level']])) { - $this->_errorsByLevel[$err['level']] = array(); - } - $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; - } - if ($log) { - if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { - $this->_log($err); - } - } - if ($die) { - die(); - } - if ($this->_compat && $push) { - return $this->raiseError($msg, $code, null, null, $err); - } - return $err; - } - - /** - * Static version of {@link push()} - * - * @param string $package Package name this error belongs to - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. see docs for {@link push()} - * @static - */ - function staticPush($package, $code, $level = 'error', $params = array(), - $msg = false, $repackage = false, $backtrace = false) - { - $s = &PEAR_ErrorStack::singleton($package); - if ($s->_contextCallback) { - if (!$backtrace) { - if (function_exists('debug_backtrace')) { - $backtrace = debug_backtrace(); - } - } - } - return $s->push($code, $level, $params, $msg, $repackage, $backtrace); - } - - /** - * Log an error using PEAR::Log - * @param array $err Error array - * @param array $levels Error level => Log constant map - * @access protected - */ - function _log($err) - { - if ($this->_logger) { - $logger = &$this->_logger; - } else { - $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; - } - if (is_a($logger, 'Log')) { - $levels = array( - 'exception' => PEAR_LOG_CRIT, - 'alert' => PEAR_LOG_ALERT, - 'critical' => PEAR_LOG_CRIT, - 'error' => PEAR_LOG_ERR, - 'warning' => PEAR_LOG_WARNING, - 'notice' => PEAR_LOG_NOTICE, - 'info' => PEAR_LOG_INFO, - 'debug' => PEAR_LOG_DEBUG); - if (isset($levels[$err['level']])) { - $level = $levels[$err['level']]; - } else { - $level = PEAR_LOG_INFO; - } - $logger->log($err['message'], $level, $err); - } else { // support non-standard logs - call_user_func($logger, $err); - } - } - - - /** - * Pop an error off of the error stack - * - * @return false|array - * @since 0.4alpha it is no longer possible to specify a specific error - * level to return - the last error pushed will be returned, instead - */ - function pop() - { - $err = @array_shift($this->_errors); - if (!is_null($err)) { - @array_pop($this->_errorsByLevel[$err['level']]); - if (!count($this->_errorsByLevel[$err['level']])) { - unset($this->_errorsByLevel[$err['level']]); - } - } - return $err; - } - - /** - * Pop an error off of the error stack, static method - * - * @param string package name - * @return boolean - * @since PEAR1.5.0a1 - */ - function staticPop($package) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); - } - } - - /** - * Determine whether there are any errors on the stack - * @param string|array Level name. Use to determine if any errors - * of level (string), or levels (array) have been pushed - * @return boolean - */ - function hasErrors($level = false) - { - if ($level) { - return isset($this->_errorsByLevel[$level]); - } - return count($this->_errors); - } - - /** - * Retrieve all errors since last purge - * - * @param boolean set in order to empty the error stack - * @param string level name, to return only errors of a particular severity - * @return array - */ - function getErrors($purge = false, $level = false) - { - if (!$purge) { - if ($level) { - if (!isset($this->_errorsByLevel[$level])) { - return array(); - } else { - return $this->_errorsByLevel[$level]; - } - } else { - return $this->_errors; - } - } - if ($level) { - $ret = $this->_errorsByLevel[$level]; - foreach ($this->_errorsByLevel[$level] as $i => $unused) { - // entries are references to the $_errors array - $this->_errorsByLevel[$level][$i] = false; - } - // array_filter removes all entries === false - $this->_errors = array_filter($this->_errors); - unset($this->_errorsByLevel[$level]); - return $ret; - } - $ret = $this->_errors; - $this->_errors = array(); - $this->_errorsByLevel = array(); - return $ret; - } - - /** - * Determine whether there are any errors on a single error stack, or on any error stack - * - * The optional parameter can be used to test the existence of any errors without the need of - * singleton instantiation - * @param string|false Package name to check for errors - * @param string Level name to check for a particular severity - * @return boolean - * @static - */ - function staticHasErrors($package = false, $level = false) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - if ($obj->hasErrors($level)) { - return true; - } - } - return false; - } - - /** - * Get a list of all errors since last purge, organized by package - * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be - * @param boolean $purge Set to purge the error stack of existing errors - * @param string $level Set to a level name in order to retrieve only errors of a particular level - * @param boolean $merge Set to return a flat array, not organized by package - * @param array $sortfunc Function used to sort a merged array - default - * sorts by time, and should be good for most cases - * @static - * @return array - */ - function staticGetErrors($purge = false, $level = false, $merge = false, - $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) - { - $ret = array(); - if (!is_callable($sortfunc)) { - $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); - if ($test) { - if ($merge) { - $ret = array_merge($ret, $test); - } else { - $ret[$package] = $test; - } - } - } - if ($merge) { - usort($ret, $sortfunc); - } - return $ret; - } - - /** - * Error sorting function, sorts by time - * @access private - */ - function _sortErrors($a, $b) - { - if ($a['time'] == $b['time']) { - return 0; - } - if ($a['time'] < $b['time']) { - return 1; - } - return -1; - } - - /** - * Standard file/line number/function/class context callback - * - * This function uses a backtrace generated from {@link debug_backtrace()} - * and so will not work at all in PHP < 4.3.0. The frame should - * reference the frame that contains the source of the error. - * @return array|false either array('file' => file, 'line' => line, - * 'function' => function name, 'class' => class name) or - * if this doesn't work, then false - * @param unused - * @param integer backtrace frame. - * @param array Results of debug_backtrace() - * @static - */ - function getFileLine($code, $params, $backtrace = null) - { - if ($backtrace === null) { - return false; - } - $frame = 0; - $functionframe = 1; - if (!isset($backtrace[1])) { - $functionframe = 0; - } else { - while (isset($backtrace[$functionframe]['function']) && - $backtrace[$functionframe]['function'] == 'eval' && - isset($backtrace[$functionframe + 1])) { - $functionframe++; - } - } - if (isset($backtrace[$frame])) { - if (!isset($backtrace[$frame]['file'])) { - $frame++; - } - $funcbacktrace = $backtrace[$functionframe]; - $filebacktrace = $backtrace[$frame]; - $ret = array('file' => $filebacktrace['file'], - 'line' => $filebacktrace['line']); - // rearrange for eval'd code or create function errors - if (strpos($filebacktrace['file'], '(') && - preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], - $matches)) { - $ret['file'] = $matches[1]; - $ret['line'] = $matches[2] + 0; - } - if (isset($funcbacktrace['function']) && isset($backtrace[1])) { - if ($funcbacktrace['function'] != 'eval') { - if ($funcbacktrace['function'] == '__lambda_func') { - $ret['function'] = 'create_function() code'; - } else { - $ret['function'] = $funcbacktrace['function']; - } - } - } - if (isset($funcbacktrace['class']) && isset($backtrace[1])) { - $ret['class'] = $funcbacktrace['class']; - } - return $ret; - } - return false; - } - - /** - * Standard error message generation callback - * - * This method may also be called by a custom error message generator - * to fill in template values from the params array, simply - * set the third parameter to the error message template string to use - * - * The special variable %__msg% is reserved: use it only to specify - * where a message passed in by the user should be placed in the template, - * like so: - * - * Error message: %msg% - internal error - * - * If the message passed like so: - * - * - * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); - * - * - * The returned error message will be "Error message: server error 500 - - * internal error" - * @param PEAR_ErrorStack - * @param array - * @param string|false Pre-generated error message template - * @static - * @return string - */ - function getErrorMessage(&$stack, $err, $template = false) - { - if ($template) { - $mainmsg = $template; - } else { - $mainmsg = $stack->getErrorMessageTemplate($err['code']); - } - $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); - if (is_array($err['params']) && count($err['params'])) { - foreach ($err['params'] as $name => $val) { - if (is_array($val)) { - // @ is needed in case $val is a multi-dimensional array - $val = @implode(', ', $val); - } - if (is_object($val)) { - if (method_exists($val, '__toString')) { - $val = $val->__toString(); - } else { - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, - 'warning', array('obj' => get_class($val)), - 'object %obj% passed into getErrorMessage, but has no __toString() method'); - $val = 'Object'; - } - } - $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); - } - } - return $mainmsg; - } - - /** - * Standard Error Message Template generator from code - * @return string - */ - function getErrorMessageTemplate($code) - { - if (!isset($this->_errorMsgs[$code])) { - return '%__msg%'; - } - return $this->_errorMsgs[$code]; - } - - /** - * Set the Error Message Template array - * - * The array format must be: - *
    -     * array(error code => 'message template',...)
    -     * 
    - * - * Error message parameters passed into {@link push()} will be used as input - * for the error message. If the template is 'message %foo% was %bar%', and the - * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will - * be 'message one was six' - * @return string - */ - function setErrorMessageTemplate($template) - { - $this->_errorMsgs = $template; - } - - - /** - * emulate PEAR::raiseError() - * - * @return PEAR_Error - */ - function raiseError() - { - require_once 'phar://go-pear.phar/' . 'PEAR.php'; - $args = func_get_args(); - return call_user_func_array(array('PEAR', 'raiseError'), $args); - } -} -$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); -$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); -?> - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Frontend.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Include error handling - */ -//require_once 'PEAR.php'; - -/** - * Which user interface class is being used. - * @var string class name - */ -$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; - -/** - * Instance of $_PEAR_Command_uiclass. - * @var object - */ -$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; - -/** - * Singleton-based frontend for PEAR user input/output - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Frontend extends PEAR -{ - /** - * Retrieve the frontend object - * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk - * @static - */ - function &singleton($type = null) - { - if ($type === null) { - if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { - $a = false; - return $a; - } - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - $a = PEAR_Frontend::setFrontendClass($type); - return $a; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to conform to the PEAR naming standard of - * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) - * @param string $uiclass full class name - * @return PEAR_Frontend - * @static - */ - function &setFrontendClass($uiclass) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!class_exists($uiclass)) { - $file = 'phar://go-pear.phar/' . str_replace('_', '/', $uiclass) . '.php'; - if (PEAR_Frontend::isIncludeable($file)) { - include_once $file; - } - } - - if (class_exists($uiclass)) { - $obj = &new $uiclass; - // quick test to see if this class implements a few of the most - // important frontend methods - if (is_a($obj, 'PEAR_Frontend')) { - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; - return $obj; - } - - $err = PEAR::raiseError("not a frontend class: $uiclass"); - return $err; - } - - $err = PEAR::raiseError("no such class: $uiclass"); - return $err; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to be a descendant of PEAR_Frontend - * @param PEAR_Frontend - * @return PEAR_Frontend - * @static - */ - function &setFrontendObject($uiobject) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!is_a($uiobject, 'PEAR_Frontend')) { - $err = PEAR::raiseError('not a valid frontend class: (' . - get_class($uiobject) . ')'); - return $err; - } - - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); - return $uiobject; - } - - /** - * @param string $path relative or absolute include path - * @return boolean - * @static - */ - function isIncludeable($path) - { - if (file_exists($path) && is_readable($path)) { - return true; - } - - $fp = @fopen($path, 'r', true); - if ($fp) { - fclose($fp); - return true; - } - - return false; - } - - /** - * @param PEAR_Config - */ - function setConfig(&$config) - { - } - - /** - * This can be overridden to allow session-based temporary file management - * - * By default, all files are deleted at the end of a session. The web installer - * needs to be able to sustain a list over many sessions in order to support - * user interaction with install scripts - */ - function addTempFile($file) - { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; - } - - /** - * Log an action - * - * @param string $msg the message to log - * @param boolean $append_crlf - * @return boolean true - * @abstract - */ - function log($msg, $append_crlf = true) - { - } - - /** - * Run a post-installation script - * - * @param array $scripts array of post-install scripts - * @abstract - */ - function runPostinstallScripts(&$scripts) - { - } - - /** - * Display human-friendly output formatted depending on the - * $command parameter. - * - * This should be able to handle basic output data with no command - * @param mixed $data data structure containing the information to display - * @param string $command command from which this method was called - * @abstract - */ - function outputData($data, $command = '_default') - { - } - - /** - * Display a modal form dialog and return the given input - * - * A frontend that requires multiple requests to retrieve and process - * data must take these needs into account, and implement the request - * handling code. - * @param string $command command from which this method was called - * @param array $prompts associative array. keys are the input field names - * and values are the description - * @param array $types array of input field types (text, password, - * etc.) keys have to be the same like in $prompts - * @param array $defaults array of default values. again keys have - * to be the same like in $prompts. Do not depend - * on a default value being set. - * @return array input sent by the user - * @abstract - */ - function userDialog($command, $prompts, $types = array(), $defaults = array()) - { - } -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: CLI.php 278236 2009-04-04 00:09:14Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ -/** - * base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php'; - -/** - * Command-line Frontend for the PEAR Installer - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Frontend_CLI extends PEAR_Frontend -{ - /** - * What type of user interface this frontend is for. - * @var string - * @access public - */ - var $type = 'CLI'; - var $lp = ''; // line prefix - - var $params = array(); - var $term = array( - 'bold' => '', - 'normal' => '', - ); - - function PEAR_Frontend_CLI() - { - parent::PEAR(); - $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 - if (function_exists('posix_isatty') && !posix_isatty(1)) { - // output is being redirected to a file or through a pipe - } elseif ($term) { - if (preg_match('/^(xterm|vt220|linux)/', $term)) { - $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); - $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109); - } elseif (preg_match('/^vt100/', $term)) { - $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); - $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); - } - } elseif (OS_WINDOWS) { - // XXX add ANSI codes here - } - } - - /** - * @param object PEAR_Error object - */ - function displayError($e) - { - return $this->_displayLine($e->getMessage()); - } - - /** - * @param object PEAR_Error object - */ - function displayFatalError($eobj) - { - $this->displayError($eobj); - if (class_exists('PEAR_Config')) { - $config = &PEAR_Config::singleton(); - if ($config->get('verbose') > 5) { - if (function_exists('debug_print_backtrace')) { - debug_print_backtrace(); - exit(1); - } - - $raised = false; - foreach (debug_backtrace() as $i => $frame) { - if (!$raised) { - if (isset($frame['class']) - && strtolower($frame['class']) == 'pear' - && strtolower($frame['function']) == 'raiseerror' - ) { - $raised = true; - } else { - continue; - } - } - - $frame['class'] = !isset($frame['class']) ? '' : $frame['class']; - $frame['type'] = !isset($frame['type']) ? '' : $frame['type']; - $frame['function'] = !isset($frame['function']) ? '' : $frame['function']; - $frame['line'] = !isset($frame['line']) ? '' : $frame['line']; - $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); - } - } - } - - exit(1); - } - - /** - * Instruct the runInstallScript method to skip a paramgroup that matches the - * id value passed in. - * - * This method is useful for dynamically configuring which sections of a post-install script - * will be run based on the user's setup, which is very useful for making flexible - * post-install scripts without losing the cross-Frontend ability to retrieve user input - * @param string - */ - function skipParamgroup($id) - { - $this->_skipSections[$id] = true; - } - - function runPostinstallScripts(&$scripts) - { - foreach ($scripts as $i => $script) { - $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); - } - } - - /** - * @param array $xml contents of postinstallscript tag - * @param object $script post-installation script - * @param string install|upgrade - */ - function runInstallScript($xml, &$script) - { - $this->_skipSections = array(); - if (!is_array($xml) || !isset($xml['paramgroup'])) { - $script->run(array(), '_default'); - return; - } - - $completedPhases = array(); - if (!isset($xml['paramgroup'][0])) { - $xml['paramgroup'] = array($xml['paramgroup']); - } - - foreach ($xml['paramgroup'] as $group) { - if (isset($this->_skipSections[$group['id']])) { - // the post-install script chose to skip this section dynamically - continue; - } - - if (isset($group['name'])) { - $paramname = explode('::', $group['name']); - if ($lastgroup['id'] != $paramname[0]) { - continue; - } - - $group['name'] = $paramname[1]; - if (!isset($answers)) { - return; - } - - if (isset($answers[$group['name']])) { - switch ($group['conditiontype']) { - case '=' : - if ($answers[$group['name']] != $group['value']) { - continue 2; - } - break; - case '!=' : - if ($answers[$group['name']] == $group['value']) { - continue 2; - } - break; - case 'preg_match' : - if (!@preg_match('/' . $group['value'] . '/', - $answers[$group['name']])) { - continue 2; - } - break; - default : - return; - } - } - } - - $lastgroup = $group; - if (isset($group['instructions'])) { - $this->_display($group['instructions']); - } - - if (!isset($group['param'][0])) { - $group['param'] = array($group['param']); - } - - if (isset($group['param'])) { - if (method_exists($script, 'postProcessPrompts')) { - $prompts = $script->postProcessPrompts($group['param'], $group['id']); - if (!is_array($prompts) || count($prompts) != count($group['param'])) { - $this->outputData('postinstall', 'Error: post-install script did not ' . - 'return proper post-processed prompts'); - $prompts = $group['param']; - } else { - foreach ($prompts as $i => $var) { - if (!is_array($var) || !isset($var['prompt']) || - !isset($var['name']) || - ($var['name'] != $group['param'][$i]['name']) || - ($var['type'] != $group['param'][$i]['type']) - ) { - $this->outputData('postinstall', 'Error: post-install script ' . - 'modified the variables or prompts, severe security risk. ' . - 'Will instead use the defaults from the package.xml'); - $prompts = $group['param']; - } - } - } - - $answers = $this->confirmDialog($prompts); - } else { - $answers = $this->confirmDialog($group['param']); - } - } - - if ((isset($answers) && $answers) || !isset($group['param'])) { - if (!isset($answers)) { - $answers = array(); - } - - array_unshift($completedPhases, $group['id']); - if (!$script->run($answers, $group['id'])) { - $script->run($completedPhases, '_undoOnError'); - return; - } - } else { - $script->run($completedPhases, '_undoOnError'); - return; - } - } - } - - /** - * Ask for user input, confirm the answers and continue until the user is satisfied - * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => - * 'text to display', 'type' => 'string'[, default => 'default value']) - * @return array - */ - function confirmDialog($params) - { - $answers = $prompts = $types = array(); - foreach ($params as $param) { - $prompts[$param['name']] = $param['prompt']; - $types[$param['name']] = $param['type']; - $answers[$param['name']] = isset($param['default']) ? $param['default'] : ''; - } - - $tried = false; - do { - if ($tried) { - $i = 1; - foreach ($answers as $var => $value) { - if (!strlen($value)) { - echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); - } - $i++; - } - } - - $answers = $this->userDialog('', $prompts, $types, $answers); - $tried = true; - } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); - - return $answers; - } - - function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20) - { - if (!is_array($prompts)) { - return array(); - } - - $testprompts = array_keys($prompts); - $result = $defaults; - - reset($prompts); - if (count($prompts) === 1) { - foreach ($prompts as $key => $prompt) { - $type = $types[$key]; - $default = @$defaults[$key]; - print "$prompt "; - if ($default) { - print "[$default] "; - } - print ": "; - - $line = fgets(STDIN, 2048); - $result[$key] = ($default && trim($line) == '') ? $default : trim($line); - } - - return $result; - } - - $first_run = true; - while (true) { - $descLength = max(array_map('strlen', $prompts)); - $descFormat = "%-{$descLength}s"; - $last = count($prompts); - - $i = 0; - foreach ($prompts as $n => $var) { - $res = isset($result[$n]) ? $result[$n] : null; - printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res); - } - print "\n1-$last, 'all', 'abort', or Enter to continue: "; - - $tmp = trim(fgets(STDIN, 1024)); - if (empty($tmp)) { - break; - } - - if ($tmp == 'abort') { - return false; - } - - if (isset($testprompts[(int)$tmp - 1])) { - $var = $testprompts[(int)$tmp - 1]; - $desc = $prompts[$var]; - $current = @$result[$var]; - print "$desc [$current] : "; - $tmp = trim(fgets(STDIN, 1024)); - if ($tmp !== '') { - $result[$var] = $tmp; - } - } elseif ($tmp == 'all') { - foreach ($prompts as $var => $desc) { - $current = $result[$var]; - print "$desc [$current] : "; - $tmp = trim(fgets(STDIN, 1024)); - if (trim($tmp) !== '') { - $result[$var] = trim($tmp); - } - } - } - - $first_run = false; - } - - return $result; - } - - function userConfirm($prompt, $default = 'yes') - { - trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); - static $positives = array('y', 'yes', 'on', '1'); - static $negatives = array('n', 'no', 'off', '0'); - print "$this->lp$prompt [$default] : "; - $fp = fopen("php://stdin", "r"); - $line = fgets($fp, 2048); - fclose($fp); - $answer = strtolower(trim($line)); - if (empty($answer)) { - $answer = $default; - } - if (in_array($answer, $positives)) { - return true; - } - if (in_array($answer, $negatives)) { - return false; - } - if (in_array($default, $positives)) { - return true; - } - return false; - } - - function outputData($data, $command = '_default') - { - switch ($command) { - case 'channel-info': - foreach ($data as $type => $section) { - if ($type == 'main') { - $section['data'] = array_values($section['data']); - } - - $this->outputData($section); - } - break; - case 'install': - case 'upgrade': - case 'upgrade-all': - if (isset($data['release_warnings'])) { - $this->_displayLine(''); - $this->_startTable(array( - 'border' => false, - 'caption' => 'Release Warnings' - )); - $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); - $this->_endTable(); - $this->_displayLine(''); - } - - $this->_displayLine($data['data']); - break; - case 'search': - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); - } - - foreach($data['data'] as $category) { - foreach($category as $pkg) { - $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); - } - } - - $this->_endTable(); - break; - case 'list-all': - if (!isset($data['data'])) { - $this->_displayLine('No packages in channel'); - break; - } - - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); - } - - foreach($data['data'] as $category) { - foreach($category as $pkg) { - unset($pkg[4], $pkg[5]); - $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); - } - } - - $this->_endTable(); - break; - case 'config-show': - $data['border'] = false; - $opts = array( - 0 => array('wrap' => 30), - 1 => array('wrap' => 20), - 2 => array('wrap' => 35) - ); - - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), $opts); - } - - foreach ($data['data'] as $group) { - foreach ($group as $value) { - if ($value[2] == '') { - $value[2] = ""; - } - - $this->_tableRow($value, null, $opts); - } - } - - $this->_endTable(); - break; - case 'remote-info': - $d = $data; - $data = array( - 'caption' => 'Package details:', - 'border' => false, - 'data' => array( - array("Latest", $data['stable']), - array("Installed", $data['installed']), - array("Package", $data['name']), - array("License", $data['license']), - array("Category", $data['category']), - array("Summary", $data['summary']), - array("Description", $data['description']), - ), - ); - - if (isset($d['deprecated']) && $d['deprecated']) { - $conf = &PEAR_Config::singleton(); - $reg = $conf->getRegistry(); - $name = $reg->parsedPackageNameToString($d['deprecated'], true); - $data['data'][] = array('Deprecated! use', $name); - } - default: { - if (is_array($data)) { - $this->_startTable($data); - $count = count($data['data'][0]); - if ($count == 2) { - $opts = array(0 => array('wrap' => 25), - 1 => array('wrap' => 48) - ); - } elseif ($count == 3) { - $opts = array(0 => array('wrap' => 30), - 1 => array('wrap' => 20), - 2 => array('wrap' => 35) - ); - } else { - $opts = null; - } - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], - array('bold' => true), - $opts); - } - - foreach($data['data'] as $row) { - $this->_tableRow($row, null, $opts); - } - $this->_endTable(); - } else { - $this->_displayLine($data); - } - } - } - } - - function log($text, $append_crlf = true) - { - if ($append_crlf) { - return $this->_displayLine($text); - } - - return $this->_display($text); - } - - function bold($text) - { - if (empty($this->term['bold'])) { - return strtoupper($text); - } - - return $this->term['bold'] . $text . $this->term['normal']; - } - - function _displayHeading($title) - { - print $this->lp.$this->bold($title)."\n"; - print $this->lp.str_repeat("=", strlen($title))."\n"; - } - - function _startTable($params = array()) - { - $params['table_data'] = array(); - $params['widest'] = array(); // indexed by column - $params['highest'] = array(); // indexed by row - $params['ncols'] = 0; - $this->params = $params; - } - - function _tableRow($columns, $rowparams = array(), $colparams = array()) - { - $highest = 1; - for ($i = 0; $i < count($columns); $i++) { - $col = &$columns[$i]; - if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { - $col = wordwrap($col, $colparams[$i]['wrap']); - } - - if (strpos($col, "\n") !== false) { - $multiline = explode("\n", $col); - $w = 0; - foreach ($multiline as $n => $line) { - $len = strlen($line); - if ($len > $w) { - $w = $len; - } - } - $lines = count($multiline); - } else { - $w = strlen($col); - } - - if (isset($this->params['widest'][$i])) { - if ($w > $this->params['widest'][$i]) { - $this->params['widest'][$i] = $w; - } - } else { - $this->params['widest'][$i] = $w; - } - - $tmp = count_chars($columns[$i], 1); - // handle unix, mac and windows formats - $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; - if ($lines > $highest) { - $highest = $lines; - } - } - - if (count($columns) > $this->params['ncols']) { - $this->params['ncols'] = count($columns); - } - - $new_row = array( - 'data' => $columns, - 'height' => $highest, - 'rowparams' => $rowparams, - 'colparams' => $colparams, - ); - $this->params['table_data'][] = $new_row; - } - - function _endTable() - { - extract($this->params); - if (!empty($caption)) { - $this->_displayHeading($caption); - } - - if (count($table_data) === 0) { - return; - } - - if (!isset($width)) { - $width = $widest; - } else { - for ($i = 0; $i < $ncols; $i++) { - if (!isset($width[$i])) { - $width[$i] = $widest[$i]; - } - } - } - - $border = false; - if (empty($border)) { - $cellstart = ''; - $cellend = ' '; - $rowend = ''; - $padrowend = false; - $borderline = ''; - } else { - $cellstart = '| '; - $cellend = ' '; - $rowend = '|'; - $padrowend = true; - $borderline = '+'; - foreach ($width as $w) { - $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); - $borderline .= '+'; - } - } - - if ($borderline) { - $this->_displayLine($borderline); - } - - for ($i = 0; $i < count($table_data); $i++) { - extract($table_data[$i]); - if (!is_array($rowparams)) { - $rowparams = array(); - } - - if (!is_array($colparams)) { - $colparams = array(); - } - - $rowlines = array(); - if ($height > 1) { - for ($c = 0; $c < count($data); $c++) { - $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); - if (count($rowlines[$c]) < $height) { - $rowlines[$c] = array_pad($rowlines[$c], $height, ''); - } - } - } else { - for ($c = 0; $c < count($data); $c++) { - $rowlines[$c] = array($data[$c]); - } - } - - for ($r = 0; $r < $height; $r++) { - $rowtext = ''; - for ($c = 0; $c < count($data); $c++) { - if (isset($colparams[$c])) { - $attribs = array_merge($rowparams, $colparams); - } else { - $attribs = $rowparams; - } - - $w = isset($width[$c]) ? $width[$c] : 0; - //$cell = $data[$c]; - $cell = $rowlines[$c][$r]; - $l = strlen($cell); - if ($l > $w) { - $cell = substr($cell, 0, $w); - } - - if (isset($attribs['bold'])) { - $cell = $this->bold($cell); - } - - if ($l < $w) { - // not using str_pad here because we may - // add bold escape characters to $cell - $cell .= str_repeat(' ', $w - $l); - } - - $rowtext .= $cellstart . $cell . $cellend; - } - - if (!$border) { - $rowtext = rtrim($rowtext); - } - - $rowtext .= $rowend; - $this->_displayLine($rowtext); - } - } - - if ($borderline) { - $this->_displayLine($borderline); - } - } - - function _displayLine($text) - { - print "$this->lp$text\n"; - } - - function _display($text) - { - print $text; - } -}package2.xml100664 764 764 14772 100664 6346 - - Archive_Tar - pear.php.net - Tar file management class - This class provides handling of tar files in PHP. -It supports creating, listing, extracting and adding to tar files. -Gzip support is available if PHP has the zlib extension built-in or -loaded. Bz2 compression is also supported with the bz2 extension loaded. - - Gregory Beaver - cellog - cellog@php.net - yes - - - Vincent Blavet - vblavet - vincent@phpconcept.net - no - - - Stig Bakken - ssb - stig@php.net - no - - 2009-03-27 - - - 1.3.3 - 1.3.1 - - - stable - stable - - New BSD License - -Change the license to New BSD license - - minor bugfix release - * fix Bug #9921 compression with bzip2 fails [cellog] - * fix Bug #11594 _readLongHeader leaves 0 bytes in filename [jamessas] - * fix Bug #11769 Incorrect symlink handing [fajar99] - - - - - - - - - PEAR - pear.php.net - 1.4.0 - 1.5.0RC2 - - - - - 4.3.0 - - - 1.5.4 - - - - - - - - 1.3.2 - 1.3.1 - - - stable - stable - - 2007-01-03 - PHP License - -Correct Bug #4016 -Remove duplicate remove error display with '@' -Correct Bug #3909 : Check existence of OS_WINDOWS constant -Correct Bug #5452 fix for "lone zero block" when untarring packages -Change filemode (from pear-core/Archive/Tar.php v.1.21) -Correct Bug #6486 Can not extract symlinks -Correct Bug #6933 Archive_Tar (Tar file management class) Directory traversal -Correct Bug #8114 Files added on-the-fly not storing date -Correct Bug #9352 Bug on _dirCheck function over nfs path - - - - - 1.3.1 - 1.3.1 - - - stable - stable - - 2005-03-17 - PHP License - -Correct Bug #3855 - - - - - 1.3.0 - 1.3.0 - - - stable - stable - - 2005-03-06 - PHP License - -Bugs correction (2475, 2488, 2135, 2176) - - - - - 1.2 - 1.2 - - - stable - stable - - 2004-05-08 - PHP License - -Add support for other separator than the space char and bug - correction - - - - - 1.1 - 1.1 - - - stable - stable - - 2003-05-28 - PHP License - -* Add support for BZ2 compression -* Add support for add and extract without using temporary files : methods addString() and extractInString() - - - - - 1.0 - 1.0 - - - stable - stable - - 2003-01-24 - PHP License - -Change status to stable - - - - - 0.10-b1 - 0.10-b1 - - - beta - beta - - 2003-01-08 - PHP License - -Add support for long filenames (greater than 99 characters) - - - - - 0.9 - 0.9 - - - stable - stable - - 2002-05-27 - PHP License - -Auto-detect gzip'ed files - - - - - 0.4 - 0.4 - - - stable - stable - - 2002-05-20 - PHP License - -Windows bugfix: use forward slashes inside archives - - - - - 0.2 - 0.2 - - - stable - stable - - 2002-02-18 - PHP License - -From initial commit to stable - - - - - 0.3 - 0.3 - - - stable - stable - - 2002-04-13 - PHP License - -Windows bugfix: used wrong directory separators - - - - -Archive_Tar-1.3.3/Archive/Tar.php100777 764 764 171523 100777 11646 - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * @category File_Formats - * @package Archive_Tar - * @author Vincent Blavet - * @copyright 1997-2008 The Authors - * @license http://www.opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Tar.php,v 1.43 2008/10/30 17:58:42 dufuz Exp $ - * @link http://pear.php.net/package/Archive_Tar - */ - -require_once 'PEAR.php'; - - -define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001); -define ('ARCHIVE_TAR_END_BLOCK', pack("a512", '')); - -/** -* Creates a (compressed) Tar archive -* -* @author Vincent Blavet -* @version $Revision: 1.43 $ -* @license http://www.opensource.org/licenses/bsd-license.php New BSD License -* @package Archive_Tar -*/ -class Archive_Tar extends PEAR -{ - /** - * @var string Name of the Tar - */ - var $_tarname=''; - - /** - * @var boolean if true, the Tar file will be gzipped - */ - var $_compress=false; - - /** - * @var string Type of compression : 'none', 'gz' or 'bz2' - */ - var $_compress_type='none'; - - /** - * @var string Explode separator - */ - var $_separator=' '; - - /** - * @var file descriptor - */ - var $_file=0; - - /** - * @var string Local Tar name of a remote Tar (http:// or ftp://) - */ - var $_temp_tarname=''; - - // {{{ constructor - /** - * Archive_Tar Class constructor. This flavour of the constructor only - * declare a new Archive_Tar object, identifying it by the name of the - * tar file. - * If the compress argument is set the tar will be read or created as a - * gzip or bz2 compressed TAR file. - * - * @param string $p_tarname The name of the tar archive to create - * @param string $p_compress can be null, 'gz' or 'bz2'. This - * parameter indicates if gzip or bz2 compression - * is required. For compatibility reason the - * boolean value 'true' means 'gz'. - * @access public - */ - function Archive_Tar($p_tarname, $p_compress = null) - { - $this->PEAR(); - $this->_compress = false; - $this->_compress_type = 'none'; - if (($p_compress === null) || ($p_compress == '')) { - if (@file_exists($p_tarname)) { - if ($fp = @fopen($p_tarname, "rb")) { - // look for gzip magic cookie - $data = fread($fp, 2); - fclose($fp); - if ($data == "\37\213") { - $this->_compress = true; - $this->_compress_type = 'gz'; - // No sure it's enought for a magic code .... - } elseif ($data == "BZ") { - $this->_compress = true; - $this->_compress_type = 'bz2'; - } - } - } else { - // probably a remote file or some file accessible - // through a stream interface - if (substr($p_tarname, -2) == 'gz') { - $this->_compress = true; - $this->_compress_type = 'gz'; - } elseif ((substr($p_tarname, -3) == 'bz2') || - (substr($p_tarname, -2) == 'bz')) { - $this->_compress = true; - $this->_compress_type = 'bz2'; - } - } - } else { - if (($p_compress === true) || ($p_compress == 'gz')) { - $this->_compress = true; - $this->_compress_type = 'gz'; - } else if ($p_compress == 'bz2') { - $this->_compress = true; - $this->_compress_type = 'bz2'; - } else { - die("Unsupported compression type '$p_compress'\n". - "Supported types are 'gz' and 'bz2'.\n"); - return false; - } - } - $this->_tarname = $p_tarname; - if ($this->_compress) { // assert zlib or bz2 extension support - if ($this->_compress_type == 'gz') - $extname = 'zlib'; - else if ($this->_compress_type == 'bz2') - $extname = 'bz2'; - - if (!extension_loaded($extname)) { - PEAR::loadExtension($extname); - } - if (!extension_loaded($extname)) { - die("The extension '$extname' couldn't be found.\n". - "Please make sure your version of PHP was built ". - "with '$extname' support.\n"); - return false; - } - } - } - // }}} - - // {{{ destructor - function _Archive_Tar() - { - $this->_close(); - // ----- Look for a local copy to delete - if ($this->_temp_tarname != '') - @unlink($this->_temp_tarname); - $this->_PEAR(); - } - // }}} - - // {{{ create() - /** - * This method creates the archive file and add the files / directories - * that are listed in $p_filelist. - * If a file with the same name exist and is writable, it is replaced - * by the new tar. - * The method return false and a PEAR error text. - * The $p_filelist parameter can be an array of string, each string - * representing a filename or a directory name with their path if - * needed. It can also be a single string with names separated by a - * single blank. - * For each directory added in the archive, the files and - * sub-directories are also added. - * See also createModify() method for more details. - * - * @param array $p_filelist An array of filenames and directory names, or a - * single string with names separated by a single - * blank space. - * @return true on success, false on error. - * @see createModify() - * @access public - */ - function create($p_filelist) - { - return $this->createModify($p_filelist, '', ''); - } - // }}} - - // {{{ add() - /** - * This method add the files / directories that are listed in $p_filelist in - * the archive. If the archive does not exist it is created. - * The method return false and a PEAR error text. - * The files and directories listed are only added at the end of the archive, - * even if a file with the same name is already archived. - * See also createModify() method for more details. - * - * @param array $p_filelist An array of filenames and directory names, or a - * single string with names separated by a single - * blank space. - * @return true on success, false on error. - * @see createModify() - * @access public - */ - function add($p_filelist) - { - return $this->addModify($p_filelist, '', ''); - } - // }}} - - // {{{ extract() - function extract($p_path='') - { - return $this->extractModify($p_path, ''); - } - // }}} - - // {{{ listContent() - function listContent() - { - $v_list_detail = array(); - - if ($this->_openRead()) { - if (!$this->_extractList('', $v_list_detail, "list", '', '')) { - unset($v_list_detail); - $v_list_detail = 0; - } - $this->_close(); - } - - return $v_list_detail; - } - // }}} - - // {{{ createModify() - /** - * This method creates the archive file and add the files / directories - * that are listed in $p_filelist. - * If the file already exists and is writable, it is replaced by the - * new tar. It is a create and not an add. If the file exists and is - * read-only or is a directory it is not replaced. The method return - * false and a PEAR error text. - * The $p_filelist parameter can be an array of string, each string - * representing a filename or a directory name with their path if - * needed. It can also be a single string with names separated by a - * single blank. - * The path indicated in $p_remove_dir will be removed from the - * memorized path of each file / directory listed when this path - * exists. By default nothing is removed (empty path '') - * The path indicated in $p_add_dir will be added at the beginning of - * the memorized path of each file / directory listed. However it can - * be set to empty ''. The adding of a path is done after the removing - * of path. - * The path add/remove ability enables the user to prepare an archive - * for extraction in a different path than the origin files are. - * See also addModify() method for file adding properties. - * - * @param array $p_filelist An array of filenames and directory names, - * or a single string with names separated by - * a single blank space. - * @param string $p_add_dir A string which contains a path to be added - * to the memorized path of each element in - * the list. - * @param string $p_remove_dir A string which contains a path to be - * removed from the memorized path of each - * element in the list, when relevant. - * @return boolean true on success, false on error. - * @access public - * @see addModify() - */ - function createModify($p_filelist, $p_add_dir, $p_remove_dir='') - { - $v_result = true; - - if (!$this->_openWrite()) - return false; - - if ($p_filelist != '') { - if (is_array($p_filelist)) - $v_list = $p_filelist; - elseif (is_string($p_filelist)) - $v_list = explode($this->_separator, $p_filelist); - else { - $this->_cleanFile(); - $this->_error('Invalid file list'); - return false; - } - - $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir); - } - - if ($v_result) { - $this->_writeFooter(); - $this->_close(); - } else - $this->_cleanFile(); - - return $v_result; - } - // }}} - - // {{{ addModify() - /** - * This method add the files / directories listed in $p_filelist at the - * end of the existing archive. If the archive does not yet exists it - * is created. - * The $p_filelist parameter can be an array of string, each string - * representing a filename or a directory name with their path if - * needed. It can also be a single string with names separated by a - * single blank. - * The path indicated in $p_remove_dir will be removed from the - * memorized path of each file / directory listed when this path - * exists. By default nothing is removed (empty path '') - * The path indicated in $p_add_dir will be added at the beginning of - * the memorized path of each file / directory listed. However it can - * be set to empty ''. The adding of a path is done after the removing - * of path. - * The path add/remove ability enables the user to prepare an archive - * for extraction in a different path than the origin files are. - * If a file/dir is already in the archive it will only be added at the - * end of the archive. There is no update of the existing archived - * file/dir. However while extracting the archive, the last file will - * replace the first one. This results in a none optimization of the - * archive size. - * If a file/dir does not exist the file/dir is ignored. However an - * error text is send to PEAR error. - * If a file/dir is not readable the file/dir is ignored. However an - * error text is send to PEAR error. - * - * @param array $p_filelist An array of filenames and directory - * names, or a single string with names - * separated by a single blank space. - * @param string $p_add_dir A string which contains a path to be - * added to the memorized path of each - * element in the list. - * @param string $p_remove_dir A string which contains a path to be - * removed from the memorized path of - * each element in the list, when - * relevant. - * @return true on success, false on error. - * @access public - */ - function addModify($p_filelist, $p_add_dir, $p_remove_dir='') - { - $v_result = true; - - if (!$this->_isArchive()) - $v_result = $this->createModify($p_filelist, $p_add_dir, - $p_remove_dir); - else { - if (is_array($p_filelist)) - $v_list = $p_filelist; - elseif (is_string($p_filelist)) - $v_list = explode($this->_separator, $p_filelist); - else { - $this->_error('Invalid file list'); - return false; - } - - $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir); - } - - return $v_result; - } - // }}} - - // {{{ addString() - /** - * This method add a single string as a file at the - * end of the existing archive. If the archive does not yet exists it - * is created. - * - * @param string $p_filename A string which contains the full - * filename path that will be associated - * with the string. - * @param string $p_string The content of the file added in - * the archive. - * @return true on success, false on error. - * @access public - */ - function addString($p_filename, $p_string) - { - $v_result = true; - - if (!$this->_isArchive()) { - if (!$this->_openWrite()) { - return false; - } - $this->_close(); - } - - if (!$this->_openAppend()) - return false; - - // Need to check the get back to the temporary file ? .... - $v_result = $this->_addString($p_filename, $p_string); - - $this->_writeFooter(); - - $this->_close(); - - return $v_result; - } - // }}} - - // {{{ extractModify() - /** - * This method extract all the content of the archive in the directory - * indicated by $p_path. When relevant the memorized path of the - * files/dir can be modified by removing the $p_remove_path path at the - * beginning of the file/dir path. - * While extracting a file, if the directory path does not exists it is - * created. - * While extracting a file, if the file already exists it is replaced - * without looking for last modification date. - * While extracting a file, if the file already exists and is write - * protected, the extraction is aborted. - * While extracting a file, if a directory with the same name already - * exists, the extraction is aborted. - * While extracting a directory, if a file with the same name already - * exists, the extraction is aborted. - * While extracting a file/directory if the destination directory exist - * and is write protected, or does not exist but can not be created, - * the extraction is aborted. - * If after extraction an extracted file does not show the correct - * stored file size, the extraction is aborted. - * When the extraction is aborted, a PEAR error text is set and false - * is returned. However the result can be a partial extraction that may - * need to be manually cleaned. - * - * @param string $p_path The path of the directory where the - * files/dir need to by extracted. - * @param string $p_remove_path Part of the memorized path that can be - * removed if present at the beginning of - * the file/dir path. - * @return boolean true on success, false on error. - * @access public - * @see extractList() - */ - function extractModify($p_path, $p_remove_path) - { - $v_result = true; - $v_list_detail = array(); - - if ($v_result = $this->_openRead()) { - $v_result = $this->_extractList($p_path, $v_list_detail, - "complete", 0, $p_remove_path); - $this->_close(); - } - - return $v_result; - } - // }}} - - // {{{ extractInString() - /** - * This method extract from the archive one file identified by $p_filename. - * The return value is a string with the file content, or NULL on error. - * @param string $p_filename The path of the file to extract in a string. - * @return a string with the file content or NULL. - * @access public - */ - function extractInString($p_filename) - { - if ($this->_openRead()) { - $v_result = $this->_extractInString($p_filename); - $this->_close(); - } else { - $v_result = NULL; - } - - return $v_result; - } - // }}} - - // {{{ extractList() - /** - * This method extract from the archive only the files indicated in the - * $p_filelist. These files are extracted in the current directory or - * in the directory indicated by the optional $p_path parameter. - * If indicated the $p_remove_path can be used in the same way as it is - * used in extractModify() method. - * @param array $p_filelist An array of filenames and directory names, - * or a single string with names separated - * by a single blank space. - * @param string $p_path The path of the directory where the - * files/dir need to by extracted. - * @param string $p_remove_path Part of the memorized path that can be - * removed if present at the beginning of - * the file/dir path. - * @return true on success, false on error. - * @access public - * @see extractModify() - */ - function extractList($p_filelist, $p_path='', $p_remove_path='') - { - $v_result = true; - $v_list_detail = array(); - - if (is_array($p_filelist)) - $v_list = $p_filelist; - elseif (is_string($p_filelist)) - $v_list = explode($this->_separator, $p_filelist); - else { - $this->_error('Invalid string list'); - return false; - } - - if ($v_result = $this->_openRead()) { - $v_result = $this->_extractList($p_path, $v_list_detail, "partial", - $v_list, $p_remove_path); - $this->_close(); - } - - return $v_result; - } - // }}} - - // {{{ setAttribute() - /** - * This method set specific attributes of the archive. It uses a variable - * list of parameters, in the format attribute code + attribute values : - * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ','); - * @param mixed $argv variable list of attributes and values - * @return true on success, false on error. - * @access public - */ - function setAttribute() - { - $v_result = true; - - // ----- Get the number of variable list of arguments - if (($v_size = func_num_args()) == 0) { - return true; - } - - // ----- Get the arguments - $v_att_list = &func_get_args(); - - // ----- Read the attributes - $i=0; - while ($i<$v_size) { - - // ----- Look for next option - switch ($v_att_list[$i]) { - // ----- Look for options that request a string value - case ARCHIVE_TAR_ATT_SEPARATOR : - // ----- Check the number of parameters - if (($i+1) >= $v_size) { - $this->_error('Invalid number of parameters for ' - .'attribute ARCHIVE_TAR_ATT_SEPARATOR'); - return false; - } - - // ----- Get the value - $this->_separator = $v_att_list[$i+1]; - $i++; - break; - - default : - $this->_error('Unknow attribute code '.$v_att_list[$i].''); - return false; - } - - // ----- Next attribute - $i++; - } - - return $v_result; - } - // }}} - - // {{{ _error() - function _error($p_message) - { - // ----- To be completed - $this->raiseError($p_message); - } - // }}} - - // {{{ _warning() - function _warning($p_message) - { - // ----- To be completed - $this->raiseError($p_message); - } - // }}} - - // {{{ _isArchive() - function _isArchive($p_filename=NULL) - { - if ($p_filename == NULL) { - $p_filename = $this->_tarname; - } - clearstatcache(); - return @is_file($p_filename) && !@is_link($p_filename); - } - // }}} - - // {{{ _openWrite() - function _openWrite() - { - if ($this->_compress_type == 'gz') - $this->_file = @gzopen($this->_tarname, "wb9"); - else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($this->_tarname, "w"); - else if ($this->_compress_type == 'none') - $this->_file = @fopen($this->_tarname, "wb"); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - if ($this->_file == 0) { - $this->_error('Unable to open in write mode \'' - .$this->_tarname.'\''); - return false; - } - - return true; - } - // }}} - - // {{{ _openRead() - function _openRead() - { - if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') { - - // ----- Look if a local copy need to be done - if ($this->_temp_tarname == '') { - $this->_temp_tarname = uniqid('tar').'.tmp'; - if (!$v_file_from = @fopen($this->_tarname, 'rb')) { - $this->_error('Unable to open in read mode \'' - .$this->_tarname.'\''); - $this->_temp_tarname = ''; - return false; - } - if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) { - $this->_error('Unable to open in write mode \'' - .$this->_temp_tarname.'\''); - $this->_temp_tarname = ''; - return false; - } - while ($v_data = @fread($v_file_from, 1024)) - @fwrite($v_file_to, $v_data); - @fclose($v_file_from); - @fclose($v_file_to); - } - - // ----- File to open if the local copy - $v_filename = $this->_temp_tarname; - - } else - // ----- File to open if the normal Tar file - $v_filename = $this->_tarname; - - if ($this->_compress_type == 'gz') - $this->_file = @gzopen($v_filename, "rb"); - else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($v_filename, "r"); - else if ($this->_compress_type == 'none') - $this->_file = @fopen($v_filename, "rb"); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - if ($this->_file == 0) { - $this->_error('Unable to open in read mode \''.$v_filename.'\''); - return false; - } - - return true; - } - // }}} - - // {{{ _openReadWrite() - function _openReadWrite() - { - if ($this->_compress_type == 'gz') - $this->_file = @gzopen($this->_tarname, "r+b"); - else if ($this->_compress_type == 'bz2') { - $this->_error('Unable to open bz2 in read/write mode \'' - .$this->_tarname.'\' (limitation of bz2 extension)'); - return false; - } else if ($this->_compress_type == 'none') - $this->_file = @fopen($this->_tarname, "r+b"); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - if ($this->_file == 0) { - $this->_error('Unable to open in read/write mode \'' - .$this->_tarname.'\''); - return false; - } - - return true; - } - // }}} - - // {{{ _close() - function _close() - { - //if (isset($this->_file)) { - if (is_resource($this->_file)) { - if ($this->_compress_type == 'gz') - @gzclose($this->_file); - else if ($this->_compress_type == 'bz2') - @bzclose($this->_file); - else if ($this->_compress_type == 'none') - @fclose($this->_file); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - $this->_file = 0; - } - - // ----- Look if a local copy need to be erase - // Note that it might be interesting to keep the url for a time : ToDo - if ($this->_temp_tarname != '') { - @unlink($this->_temp_tarname); - $this->_temp_tarname = ''; - } - - return true; - } - // }}} - - // {{{ _cleanFile() - function _cleanFile() - { - $this->_close(); - - // ----- Look for a local copy - if ($this->_temp_tarname != '') { - // ----- Remove the local copy but not the remote tarname - @unlink($this->_temp_tarname); - $this->_temp_tarname = ''; - } else { - // ----- Remove the local tarname file - @unlink($this->_tarname); - } - $this->_tarname = ''; - - return true; - } - // }}} - - // {{{ _writeBlock() - function _writeBlock($p_binary_data, $p_len=null) - { - if (is_resource($this->_file)) { - if ($p_len === null) { - if ($this->_compress_type == 'gz') - @gzputs($this->_file, $p_binary_data); - else if ($this->_compress_type == 'bz2') - @bzwrite($this->_file, $p_binary_data); - else if ($this->_compress_type == 'none') - @fputs($this->_file, $p_binary_data); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - } else { - if ($this->_compress_type == 'gz') - @gzputs($this->_file, $p_binary_data, $p_len); - else if ($this->_compress_type == 'bz2') - @bzwrite($this->_file, $p_binary_data, $p_len); - else if ($this->_compress_type == 'none') - @fputs($this->_file, $p_binary_data, $p_len); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - } - } - return true; - } - // }}} - - // {{{ _readBlock() - function _readBlock() - { - $v_block = null; - if (is_resource($this->_file)) { - if ($this->_compress_type == 'gz') - $v_block = @gzread($this->_file, 512); - else if ($this->_compress_type == 'bz2') - $v_block = @bzread($this->_file, 512); - else if ($this->_compress_type == 'none') - $v_block = @fread($this->_file, 512); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - } - return $v_block; - } - // }}} - - // {{{ _jumpBlock() - function _jumpBlock($p_len=null) - { - if (is_resource($this->_file)) { - if ($p_len === null) - $p_len = 1; - - if ($this->_compress_type == 'gz') { - @gzseek($this->_file, gztell($this->_file)+($p_len*512)); - } - else if ($this->_compress_type == 'bz2') { - // ----- Replace missing bztell() and bzseek() - for ($i=0; $i<$p_len; $i++) - $this->_readBlock(); - } else if ($this->_compress_type == 'none') - @fseek($this->_file, ftell($this->_file)+($p_len*512)); - else - $this->_error('Unknown or missing compression type (' - .$this->_compress_type.')'); - - } - return true; - } - // }}} - - // {{{ _writeFooter() - function _writeFooter() - { - if (is_resource($this->_file)) { - // ----- Write the last 0 filled block for end of archive - $v_binary_data = pack('a1024', ''); - $this->_writeBlock($v_binary_data); - } - return true; - } - // }}} - - // {{{ _addList() - function _addList($p_list, $p_add_dir, $p_remove_dir) - { - $v_result=true; - $v_header = array(); - - // ----- Remove potential windows directory separator - $p_add_dir = $this->_translateWinPath($p_add_dir); - $p_remove_dir = $this->_translateWinPath($p_remove_dir, false); - - if (!$this->_file) { - $this->_error('Invalid file descriptor'); - return false; - } - - if (sizeof($p_list) == 0) - return true; - - foreach ($p_list as $v_filename) { - if (!$v_result) { - break; - } - - // ----- Skip the current tar name - if ($v_filename == $this->_tarname) - continue; - - if ($v_filename == '') - continue; - - if (!file_exists($v_filename)) { - $this->_warning("File '$v_filename' does not exist"); - continue; - } - - // ----- Add the file or directory header - if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) - return false; - - if (@is_dir($v_filename) && !@is_link($v_filename)) { - if (!($p_hdir = opendir($v_filename))) { - $this->_warning("Directory '$v_filename' can not be read"); - continue; - } - while (false !== ($p_hitem = readdir($p_hdir))) { - if (($p_hitem != '.') && ($p_hitem != '..')) { - if ($v_filename != ".") - $p_temp_list[0] = $v_filename.'/'.$p_hitem; - else - $p_temp_list[0] = $p_hitem; - - $v_result = $this->_addList($p_temp_list, - $p_add_dir, - $p_remove_dir); - } - } - - unset($p_temp_list); - unset($p_hdir); - unset($p_hitem); - } - } - - return $v_result; - } - // }}} - - // {{{ _addFile() - function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir) - { - if (!$this->_file) { - $this->_error('Invalid file descriptor'); - return false; - } - - if ($p_filename == '') { - $this->_error('Invalid file name'); - return false; - } - - // ----- Calculate the stored filename - $p_filename = $this->_translateWinPath($p_filename, false);; - $v_stored_filename = $p_filename; - if (strcmp($p_filename, $p_remove_dir) == 0) { - return true; - } - if ($p_remove_dir != '') { - if (substr($p_remove_dir, -1) != '/') - $p_remove_dir .= '/'; - - if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) - $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); - } - $v_stored_filename = $this->_translateWinPath($v_stored_filename); - if ($p_add_dir != '') { - if (substr($p_add_dir, -1) == '/') - $v_stored_filename = $p_add_dir.$v_stored_filename; - else - $v_stored_filename = $p_add_dir.'/'.$v_stored_filename; - } - - $v_stored_filename = $this->_pathReduction($v_stored_filename); - - if ($this->_isArchive($p_filename)) { - if (($v_file = @fopen($p_filename, "rb")) == 0) { - $this->_warning("Unable to open file '".$p_filename - ."' in binary read mode"); - return true; - } - - if (!$this->_writeHeader($p_filename, $v_stored_filename)) - return false; - - while (($v_buffer = fread($v_file, 512)) != '') { - $v_binary_data = pack("a512", "$v_buffer"); - $this->_writeBlock($v_binary_data); - } - - fclose($v_file); - - } else { - // ----- Only header for dir - if (!$this->_writeHeader($p_filename, $v_stored_filename)) - return false; - } - - return true; - } - // }}} - - // {{{ _addString() - function _addString($p_filename, $p_string) - { - if (!$this->_file) { - $this->_error('Invalid file descriptor'); - return false; - } - - if ($p_filename == '') { - $this->_error('Invalid file name'); - return false; - } - - // ----- Calculate the stored filename - $p_filename = $this->_translateWinPath($p_filename, false);; - - if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), - time(), 384, "", 0, 0)) - return false; - - $i=0; - while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') { - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - } - - return true; - } - // }}} - - // {{{ _writeHeader() - function _writeHeader($p_filename, $p_stored_filename) - { - if ($p_stored_filename == '') - $p_stored_filename = $p_filename; - $v_reduce_filename = $this->_pathReduction($p_stored_filename); - - if (strlen($v_reduce_filename) > 99) { - if (!$this->_writeLongHeader($v_reduce_filename)) - return false; - } - - $v_info = lstat($p_filename); - $v_uid = sprintf("%6s ", DecOct($v_info[4])); - $v_gid = sprintf("%6s ", DecOct($v_info[5])); - $v_perms = sprintf("%6s ", DecOct($v_info['mode'])); - - $v_mtime = sprintf("%11s", DecOct($v_info['mode'])); - - $v_linkname = ''; - - if (@is_link($p_filename)) { - $v_typeflag = '2'; - $v_linkname = readlink($p_filename); - $v_size = sprintf("%11s ", DecOct(0)); - } elseif (@is_dir($p_filename)) { - $v_typeflag = "5"; - $v_size = sprintf("%11s ", DecOct(0)); - } else { - $v_typeflag = ''; - clearstatcache(); - $v_size = sprintf("%11s ", DecOct($v_info['size'])); - } - - $v_magic = ''; - - $v_version = ''; - - $v_uname = ''; - - $v_gname = ''; - - $v_devmajor = ''; - - $v_devminor = ''; - - $v_prefix = ''; - - $v_binary_data_first = pack("a100a8a8a8a12A12", - $v_reduce_filename, $v_perms, $v_uid, - $v_gid, $v_size, $v_mtime); - $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", - $v_typeflag, $v_linkname, $v_magic, - $v_version, $v_uname, $v_gname, - $v_devmajor, $v_devminor, $v_prefix, ''); - - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum += ord(substr($v_binary_data_first,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156, $j=0; $i<512; $i++, $j++) - $v_checksum += ord(substr($v_binary_data_last,$j,1)); - - // ----- Write the first 148 bytes of the header in the archive - $this->_writeBlock($v_binary_data_first, 148); - - // ----- Write the calculated checksum - $v_checksum = sprintf("%6s ", DecOct($v_checksum)); - $v_binary_data = pack("a8", $v_checksum); - $this->_writeBlock($v_binary_data, 8); - - // ----- Write the last 356 bytes of the header in the archive - $this->_writeBlock($v_binary_data_last, 356); - - return true; - } - // }}} - - // {{{ _writeHeaderBlock() - function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, - $p_type='', $p_uid=0, $p_gid=0) - { - $p_filename = $this->_pathReduction($p_filename); - - if (strlen($p_filename) > 99) { - if (!$this->_writeLongHeader($p_filename)) - return false; - } - - if ($p_type == "5") { - $v_size = sprintf("%11s ", DecOct(0)); - } else { - $v_size = sprintf("%11s ", DecOct($p_size)); - } - - $v_uid = sprintf("%6s ", DecOct($p_uid)); - $v_gid = sprintf("%6s ", DecOct($p_gid)); - $v_perms = sprintf("%6s ", DecOct($p_perms)); - - $v_mtime = sprintf("%11s", DecOct($p_mtime)); - - $v_linkname = ''; - - $v_magic = ''; - - $v_version = ''; - - $v_uname = ''; - - $v_gname = ''; - - $v_devmajor = ''; - - $v_devminor = ''; - - $v_prefix = ''; - - $v_binary_data_first = pack("a100a8a8a8a12A12", - $p_filename, $v_perms, $v_uid, $v_gid, - $v_size, $v_mtime); - $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", - $p_type, $v_linkname, $v_magic, - $v_version, $v_uname, $v_gname, - $v_devmajor, $v_devminor, $v_prefix, ''); - - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum += ord(substr($v_binary_data_first,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156, $j=0; $i<512; $i++, $j++) - $v_checksum += ord(substr($v_binary_data_last,$j,1)); - - // ----- Write the first 148 bytes of the header in the archive - $this->_writeBlock($v_binary_data_first, 148); - - // ----- Write the calculated checksum - $v_checksum = sprintf("%6s ", DecOct($v_checksum)); - $v_binary_data = pack("a8", $v_checksum); - $this->_writeBlock($v_binary_data, 8); - - // ----- Write the last 356 bytes of the header in the archive - $this->_writeBlock($v_binary_data_last, 356); - - return true; - } - // }}} - - // {{{ _writeLongHeader() - function _writeLongHeader($p_filename) - { - $v_size = sprintf("%11s ", DecOct(strlen($p_filename))); - - $v_typeflag = 'L'; - - $v_linkname = ''; - - $v_magic = ''; - - $v_version = ''; - - $v_uname = ''; - - $v_gname = ''; - - $v_devmajor = ''; - - $v_devminor = ''; - - $v_prefix = ''; - - $v_binary_data_first = pack("a100a8a8a8a12A12", - '././@LongLink', 0, 0, 0, $v_size, 0); - $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", - $v_typeflag, $v_linkname, $v_magic, - $v_version, $v_uname, $v_gname, - $v_devmajor, $v_devminor, $v_prefix, ''); - - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum += ord(substr($v_binary_data_first,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156, $j=0; $i<512; $i++, $j++) - $v_checksum += ord(substr($v_binary_data_last,$j,1)); - - // ----- Write the first 148 bytes of the header in the archive - $this->_writeBlock($v_binary_data_first, 148); - - // ----- Write the calculated checksum - $v_checksum = sprintf("%6s ", DecOct($v_checksum)); - $v_binary_data = pack("a8", $v_checksum); - $this->_writeBlock($v_binary_data, 8); - - // ----- Write the last 356 bytes of the header in the archive - $this->_writeBlock($v_binary_data_last, 356); - - // ----- Write the filename as content of the block - $i=0; - while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') { - $v_binary_data = pack("a512", "$v_buffer"); - $this->_writeBlock($v_binary_data); - } - - return true; - } - // }}} - - // {{{ _readHeader() - function _readHeader($v_binary_data, &$v_header) - { - if (strlen($v_binary_data)==0) { - $v_header['filename'] = ''; - return true; - } - - if (strlen($v_binary_data) != 512) { - $v_header['filename'] = ''; - $this->_error('Invalid block size : '.strlen($v_binary_data)); - return false; - } - - if (!is_array($v_header)) { - $v_header = array(); - } - // ----- Calculate the checksum - $v_checksum = 0; - // ..... First part of the header - for ($i=0; $i<148; $i++) - $v_checksum+=ord(substr($v_binary_data,$i,1)); - // ..... Ignore the checksum value and replace it by ' ' (space) - for ($i=148; $i<156; $i++) - $v_checksum += ord(' '); - // ..... Last part of the header - for ($i=156; $i<512; $i++) - $v_checksum+=ord(substr($v_binary_data,$i,1)); - - $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" - ."a8checksum/a1typeflag/a100link/a6magic/a2version/" - ."a32uname/a32gname/a8devmajor/a8devminor", - $v_binary_data); - - // ----- Extract the checksum - $v_header['checksum'] = OctDec(trim($v_data['checksum'])); - if ($v_header['checksum'] != $v_checksum) { - $v_header['filename'] = ''; - - // ----- Look for last block (empty block) - if (($v_checksum == 256) && ($v_header['checksum'] == 0)) - return true; - - $this->_error('Invalid checksum for file "'.$v_data['filename'] - .'" : '.$v_checksum.' calculated, ' - .$v_header['checksum'].' expected'); - return false; - } - - // ----- Extract the properties - $v_header['filename'] = trim($v_data['filename']); - if ($this->_maliciousFilename($v_header['filename'])) { - $this->_error('Malicious .tar detected, file "' . $v_header['filename'] . - '" will not install in desired directory tree'); - return false; - } - $v_header['mode'] = OctDec(trim($v_data['mode'])); - $v_header['uid'] = OctDec(trim($v_data['uid'])); - $v_header['gid'] = OctDec(trim($v_data['gid'])); - $v_header['size'] = OctDec(trim($v_data['size'])); - $v_header['mtime'] = OctDec(trim($v_data['mtime'])); - if (($v_header['typeflag'] = $v_data['typeflag']) == "5") { - $v_header['size'] = 0; - } - $v_header['link'] = trim($v_data['link']); - /* ----- All these fields are removed form the header because - they do not carry interesting info - $v_header[magic] = trim($v_data[magic]); - $v_header[version] = trim($v_data[version]); - $v_header[uname] = trim($v_data[uname]); - $v_header[gname] = trim($v_data[gname]); - $v_header[devmajor] = trim($v_data[devmajor]); - $v_header[devminor] = trim($v_data[devminor]); - */ - - return true; - } - // }}} - - // {{{ _maliciousFilename() - /** - * Detect and report a malicious file name - * - * @param string $file - * @return bool - * @access private - */ - function _maliciousFilename($file) - { - if (strpos($file, '/../') !== false) { - return true; - } - if (strpos($file, '../') === 0) { - return true; - } - return false; - } - // }}} - - // {{{ _readLongHeader() - function _readLongHeader(&$v_header) - { - $v_filename = ''; - $n = floor($v_header['size']/512); - for ($i=0; $i<$n; $i++) { - $v_content = $this->_readBlock(); - $v_filename .= $v_content; - } - if (($v_header['size'] % 512) != 0) { - $v_content = $this->_readBlock(); - $v_filename .= $v_content; - } - - // ----- Read the next header - $v_binary_data = $this->_readBlock(); - - if (!$this->_readHeader($v_binary_data, $v_header)) - return false; - - $v_filename = trim($v_filename); - $v_header['filename'] = $v_filename; - if ($this->_maliciousFilename($v_filename)) { - $this->_error('Malicious .tar detected, file "' . $v_filename . - '" will not install in desired directory tree'); - return false; - } - - return true; - } - // }}} - - // {{{ _extractInString() - /** - * This method extract from the archive one file identified by $p_filename. - * The return value is a string with the file content, or NULL on error. - * @param string $p_filename The path of the file to extract in a string. - * @return a string with the file content or NULL. - * @access private - */ - function _extractInString($p_filename) - { - $v_result_str = ""; - - While (strlen($v_binary_data = $this->_readBlock()) != 0) - { - if (!$this->_readHeader($v_binary_data, $v_header)) - return NULL; - - if ($v_header['filename'] == '') - continue; - - // ----- Look for long filename - if ($v_header['typeflag'] == 'L') { - if (!$this->_readLongHeader($v_header)) - return NULL; - } - - if ($v_header['filename'] == $p_filename) { - if ($v_header['typeflag'] == "5") { - $this->_error('Unable to extract in string a directory ' - .'entry {'.$v_header['filename'].'}'); - return NULL; - } else { - $n = floor($v_header['size']/512); - for ($i=0; $i<$n; $i++) { - $v_result_str .= $this->_readBlock(); - } - if (($v_header['size'] % 512) != 0) { - $v_content = $this->_readBlock(); - $v_result_str .= substr($v_content, 0, - ($v_header['size'] % 512)); - } - return $v_result_str; - } - } else { - $this->_jumpBlock(ceil(($v_header['size']/512))); - } - } - - return NULL; - } - // }}} - - // {{{ _extractList() - function _extractList($p_path, &$p_list_detail, $p_mode, - $p_file_list, $p_remove_path) - { - $v_result=true; - $v_nb = 0; - $v_extract_all = true; - $v_listing = false; - - $p_path = $this->_translateWinPath($p_path, false); - if ($p_path == '' || (substr($p_path, 0, 1) != '/' - && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) { - $p_path = "./".$p_path; - } - $p_remove_path = $this->_translateWinPath($p_remove_path); - - // ----- Look for path to remove format (should end by /) - if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) - $p_remove_path .= '/'; - $p_remove_path_size = strlen($p_remove_path); - - switch ($p_mode) { - case "complete" : - $v_extract_all = TRUE; - $v_listing = FALSE; - break; - case "partial" : - $v_extract_all = FALSE; - $v_listing = FALSE; - break; - case "list" : - $v_extract_all = FALSE; - $v_listing = TRUE; - break; - default : - $this->_error('Invalid extract mode ('.$p_mode.')'); - return false; - } - - clearstatcache(); - - while (strlen($v_binary_data = $this->_readBlock()) != 0) - { - $v_extract_file = FALSE; - $v_extraction_stopped = 0; - - if (!$this->_readHeader($v_binary_data, $v_header)) - return false; - - if ($v_header['filename'] == '') { - continue; - } - - // ----- Look for long filename - if ($v_header['typeflag'] == 'L') { - if (!$this->_readLongHeader($v_header)) - return false; - } - - if ((!$v_extract_all) && (is_array($p_file_list))) { - // ----- By default no unzip if the file is not found - $v_extract_file = false; - - for ($i=0; $i strlen($p_file_list[$i])) - && (substr($v_header['filename'], 0, strlen($p_file_list[$i])) - == $p_file_list[$i])) { - $v_extract_file = TRUE; - break; - } - } - - // ----- It is a file, so compare the file names - elseif ($p_file_list[$i] == $v_header['filename']) { - $v_extract_file = TRUE; - break; - } - } - } else { - $v_extract_file = TRUE; - } - - // ----- Look if this file need to be extracted - if (($v_extract_file) && (!$v_listing)) - { - if (($p_remove_path != '') - && (substr($v_header['filename'], 0, $p_remove_path_size) - == $p_remove_path)) - $v_header['filename'] = substr($v_header['filename'], - $p_remove_path_size); - if (($p_path != './') && ($p_path != '/')) { - while (substr($p_path, -1) == '/') - $p_path = substr($p_path, 0, strlen($p_path)-1); - - if (substr($v_header['filename'], 0, 1) == '/') - $v_header['filename'] = $p_path.$v_header['filename']; - else - $v_header['filename'] = $p_path.'/'.$v_header['filename']; - } - if (file_exists($v_header['filename'])) { - if ( (@is_dir($v_header['filename'])) - && ($v_header['typeflag'] == '')) { - $this->_error('File '.$v_header['filename'] - .' already exists as a directory'); - return false; - } - if ( ($this->_isArchive($v_header['filename'])) - && ($v_header['typeflag'] == "5")) { - $this->_error('Directory '.$v_header['filename'] - .' already exists as a file'); - return false; - } - if (!is_writeable($v_header['filename'])) { - $this->_error('File '.$v_header['filename'] - .' already exists and is write protected'); - return false; - } - if (filemtime($v_header['filename']) > $v_header['mtime']) { - // To be completed : An error or silent no replace ? - } - } - - // ----- Check the directory availability and create it if necessary - elseif (($v_result - = $this->_dirCheck(($v_header['typeflag'] == "5" - ?$v_header['filename'] - :dirname($v_header['filename'])))) != 1) { - $this->_error('Unable to create path for '.$v_header['filename']); - return false; - } - - if ($v_extract_file) { - if ($v_header['typeflag'] == "5") { - if (!@file_exists($v_header['filename'])) { - if (!@mkdir($v_header['filename'], 0777)) { - $this->_error('Unable to create directory {' - .$v_header['filename'].'}'); - return false; - } - } - } elseif ($v_header['typeflag'] == "2") { - if (@file_exists($v_header['filename'])) { - @unlink($v_header['filename']); - } - if (!@symlink($v_header['link'], $v_header['filename'])) { - $this->_error('Unable to extract symbolic link {' - .$v_header['filename'].'}'); - return false; - } - } else { - if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) { - $this->_error('Error while opening {'.$v_header['filename'] - .'} in write binary mode'); - return false; - } else { - $n = floor($v_header['size']/512); - for ($i=0; $i<$n; $i++) { - $v_content = $this->_readBlock(); - fwrite($v_dest_file, $v_content, 512); - } - if (($v_header['size'] % 512) != 0) { - $v_content = $this->_readBlock(); - fwrite($v_dest_file, $v_content, ($v_header['size'] % 512)); - } - - @fclose($v_dest_file); - - // ----- Change the file mode, mtime - @touch($v_header['filename'], $v_header['mtime']); - if ($v_header['mode'] & 0111) { - // make file executable, obey umask - $mode = fileperms($v_header['filename']) | (~umask() & 0111); - @chmod($v_header['filename'], $mode); - } - } - - // ----- Check the file size - clearstatcache(); - if (filesize($v_header['filename']) != $v_header['size']) { - $this->_error('Extracted file '.$v_header['filename'] - .' does not have the correct file size \'' - .filesize($v_header['filename']) - .'\' ('.$v_header['size'] - .' expected). Archive may be corrupted.'); - return false; - } - } - } else { - $this->_jumpBlock(ceil(($v_header['size']/512))); - } - } else { - $this->_jumpBlock(ceil(($v_header['size']/512))); - } - - /* TBC : Seems to be unused ... - if ($this->_compress) - $v_end_of_file = @gzeof($this->_file); - else - $v_end_of_file = @feof($this->_file); - */ - - if ($v_listing || $v_extract_file || $v_extraction_stopped) { - // ----- Log extracted files - if (($v_file_dir = dirname($v_header['filename'])) - == $v_header['filename']) - $v_file_dir = ''; - if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) - $v_file_dir = '/'; - - $p_list_detail[$v_nb++] = $v_header; - if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) { - return true; - } - } - } - - return true; - } - // }}} - - // {{{ _openAppend() - function _openAppend() - { - if (filesize($this->_tarname) == 0) - return $this->_openWrite(); - - if ($this->_compress) { - $this->_close(); - - if (!@rename($this->_tarname, $this->_tarname.".tmp")) { - $this->_error('Error while renaming \''.$this->_tarname - .'\' to temporary file \''.$this->_tarname - .'.tmp\''); - return false; - } - - if ($this->_compress_type == 'gz') - $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb"); - elseif ($this->_compress_type == 'bz2') - $v_temp_tar = @bzopen($this->_tarname.".tmp", "r"); - - if ($v_temp_tar == 0) { - $this->_error('Unable to open file \''.$this->_tarname - .'.tmp\' in binary read mode'); - @rename($this->_tarname.".tmp", $this->_tarname); - return false; - } - - if (!$this->_openWrite()) { - @rename($this->_tarname.".tmp", $this->_tarname); - return false; - } - - if ($this->_compress_type == 'gz') { - while (!@gzeof($v_temp_tar)) { - $v_buffer = @gzread($v_temp_tar, 512); - if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { - // do not copy end blocks, we will re-make them - // after appending - continue; - } - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - } - - @gzclose($v_temp_tar); - } - elseif ($this->_compress_type == 'bz2') { - while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) { - if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { - continue; - } - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - } - - @bzclose($v_temp_tar); - } - - if (!@unlink($this->_tarname.".tmp")) { - $this->_error('Error while deleting temporary file \'' - .$this->_tarname.'.tmp\''); - } - - } else { - // ----- For not compressed tar, just add files before the last - // one or two 512 bytes block - if (!$this->_openReadWrite()) - return false; - - clearstatcache(); - $v_size = filesize($this->_tarname); - - // We might have zero, one or two end blocks. - // The standard is two, but we should try to handle - // other cases. - fseek($this->_file, $v_size - 1024); - if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { - fseek($this->_file, $v_size - 1024); - } - elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { - fseek($this->_file, $v_size - 512); - } - } - - return true; - } - // }}} - - // {{{ _append() - function _append($p_filelist, $p_add_dir='', $p_remove_dir='') - { - if (!$this->_openAppend()) - return false; - - if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) - $this->_writeFooter(); - - $this->_close(); - - return true; - } - // }}} - - // {{{ _dirCheck() - - /** - * Check if a directory exists and create it (including parent - * dirs) if not. - * - * @param string $p_dir directory to check - * - * @return bool TRUE if the directory exists or was created - */ - function _dirCheck($p_dir) - { - clearstatcache(); - if ((@is_dir($p_dir)) || ($p_dir == '')) - return true; - - $p_parent_dir = dirname($p_dir); - - if (($p_parent_dir != $p_dir) && - ($p_parent_dir != '') && - (!$this->_dirCheck($p_parent_dir))) - return false; - - if (!@mkdir($p_dir, 0777)) { - $this->_error("Unable to create directory '$p_dir'"); - return false; - } - - return true; - } - - // }}} - - // {{{ _pathReduction() - - /** - * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", - * rand emove double slashes. - * - * @param string $p_dir path to reduce - * - * @return string reduced path - * - * @access private - * - */ - function _pathReduction($p_dir) - { - $v_result = ''; - - // ----- Look for not empty path - if ($p_dir != '') { - // ----- Explode path by directory names - $v_list = explode('/', $p_dir); - - // ----- Study directories from last to first - for ($i=sizeof($v_list)-1; $i>=0; $i--) { - // ----- Look for current path - if ($v_list[$i] == ".") { - // ----- Ignore this directory - // Should be the first $i=0, but no check is done - } - else if ($v_list[$i] == "..") { - // ----- Ignore it and ignore the $i-1 - $i--; - } - else if ( ($v_list[$i] == '') - && ($i!=(sizeof($v_list)-1)) - && ($i!=0)) { - // ----- Ignore only the double '//' in path, - // but not the first and last / - } else { - $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/' - .$v_result:''); - } - } - } - $v_result = strtr($v_result, '\\', '/'); - return $v_result; - } - - // }}} - - // {{{ _translateWinPath() - function _translateWinPath($p_path, $p_remove_disk_letter=true) - { - if (defined('OS_WINDOWS') && OS_WINDOWS) { - // ----- Look for potential disk letter - if ( ($p_remove_disk_letter) - && (($v_position = strpos($p_path, ':')) != false)) { - $p_path = substr($p_path, $v_position+1); - } - // ----- Change potential windows directory separator - if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { - $p_path = strtr($p_path, '\\', '/'); - } - } - return $p_path; - } - // }}} - -} -?> -Archive_Tar-1.3.3/docs/Archive_Tar.txt100777 764 764 43673 100777 12672 Documentation for class Archive_Tar -=================================== -Last update : 2001-08-15 - - - -Overview : ----------- - - The Archive_Tar class helps in creating and managing GNU TAR format - files compressed by GNU ZIP or not. - The class offers basic functions like creating an archive, adding - files in the archive, extracting files from the archive and listing - the archive content. - It also provide advanced functions that allow the adding and - extraction of files with path manipulation. - - -Sample : --------- - - // ----- Creating the object (uncompressed archive) - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->setErrorHandling(PEAR_ERROR_PRINT); - - // ----- Creating the archive - $v_list[0]="file.txt"; - $v_list[1]="data/"; - $v_list[2]="file.log"; - $tar_object->create($v_list); - - // ----- Adding files - $v_list[0]="dev/file.txt"; - $v_list[1]="dev/data/"; - $v_list[2]="log/file.log"; - $tar_object->add($v_list); - - // ----- Adding more files - $tar_object->add("release/newfile.log release/readme.txt"); - - // ----- Listing the content - if (($v_list = $tar_object->listContent()) != 0) - for ($i=0; $i"; - echo " .size :'".$v_list[$i][size]."'
    "; - echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")
    "; - echo " .mode :'".$v_list[$i][mode]."'
    "; - echo " .uid :'".$v_list[$i][uid]."'
    "; - echo " .gid :'".$v_list[$i][gid]."'
    "; - echo " .typeflag :'".$v_list[$i][typeflag]."'
    "; - } - - // ----- Extracting the archive in directory "install" - $tar_object->extract("install"); - - -Public arguments : ------------------- - -None - - -Public Methods : ----------------- - -Method : Archive_Tar($p_tarname, $compress = null) -Description : - Archive_Tar Class constructor. This flavour of the constructor only - declare a new Archive_Tar object, identifying it by the name of the - tar file. - If the compress argument is set the tar will be read or created as a - gzip or bz2 compressed TAR file. -Arguments : - $p_tarname : A valid filename for the tar archive file. - $p_compress : can be null, 'gz' or 'bz2'. For - compatibility reason it can also be true. This - parameter indicates if gzip or bz2 compression - is required. -Return value : - The Archive_Tar object. -Sample : - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object_compressed = new Archive_Tar("tarname.tgz", true); -How it works : - Initialize the object. - -Method : create($p_filelist) -Description : - This method creates the archive file and add the files / directories - that are listed in $p_filelist. - If the file already exists and is writable, it is replaced by the - new tar. It is a create and not an add. If the file exists and is - read-only or is a directory it is not replaced. The method return - false and a PEAR error text. - The $p_filelist parameter can be an array of string, each string - representing a filename or a directory name with their path if - needed. It can also be a single string with names separated by a - single blank. - See also createModify() method for more details. -Arguments : - $p_filelist : An array of filenames and directory names, or a single - string with names separated by a single blank space. -Return value : - true on success, false on error. -Sample 1 : - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling - $v_list[0]="file.txt"; - $v_list[1]="data/"; (Optional '/' at the end) - $v_list[2]="file.log"; - $tar_object->create($v_list); -Sample 2 : - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling - $tar_object->create("file.txt data/ file.log"); -How it works : - Just calling the createModify() method with the right parameters. - -Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "") -Description : - This method creates the archive file and add the files / directories - that are listed in $p_filelist. - If the file already exists and is writable, it is replaced by the - new tar. It is a create and not an add. If the file exists and is - read-only or is a directory it is not replaced. The method return - false and a PEAR error text. - The $p_filelist parameter can be an array of string, each string - representing a filename or a directory name with their path if - needed. It can also be a single string with names separated by a - single blank. - The path indicated in $p_remove_dir will be removed from the - memorized path of each file / directory listed when this path - exists. By default nothing is removed (empty path "") - The path indicated in $p_add_dir will be added at the beginning of - the memorized path of each file / directory listed. However it can - be set to empty "". The adding of a path is done after the removing - of path. - The path add/remove ability enables the user to prepare an archive - for extraction in a different path than the origin files are. - See also addModify() method for file adding properties. -Arguments : - $p_filelist : An array of filenames and directory names, or a single - string with names separated by a single blank space. - $p_add_dir : A string which contains a path to be added to the - memorized path of each element in the list. - $p_remove_dir : A string which contains a path to be removed from - the memorized path of each element in the list, when - relevant. -Return value : - true on success, false on error. -Sample 1 : - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling - $v_list[0]="file.txt"; - $v_list[1]="data/"; (Optional '/' at the end) - $v_list[2]="file.log"; - $tar_object->createModify($v_list, "install"); - // files are stored in the archive as : - // install/file.txt - // install/data - // install/data/file1.txt - // install/data/... all the files and sub-dirs of data/ - // install/file.log -Sample 2 : - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling - $v_list[0]="dev/file.txt"; - $v_list[1]="dev/data/"; (Optional '/' at the end) - $v_list[2]="log/file.log"; - $tar_object->createModify($v_list, "install", "dev"); - // files are stored in the archive as : - // install/file.txt - // install/data - // install/data/file1.txt - // install/data/... all the files and sub-dirs of data/ - // install/log/file.log -How it works : - Open the file in write mode (erasing the existing one if one), - call the _addList() method for adding the files in an empty archive, - add the tar footer (512 bytes block), close the tar file. - - -Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="") -Description : - This method add the files / directories listed in $p_filelist at the - end of the existing archive. If the archive does not yet exists it - is created. - The $p_filelist parameter can be an array of string, each string - representing a filename or a directory name with their path if - needed. It can also be a single string with names separated by a - single blank. - The path indicated in $p_remove_dir will be removed from the - memorized path of each file / directory listed when this path - exists. By default nothing is removed (empty path "") - The path indicated in $p_add_dir will be added at the beginning of - the memorized path of each file / directory listed. However it can - be set to empty "". The adding of a path is done after the removing - of path. - The path add/remove ability enables the user to prepare an archive - for extraction in a different path than the origin files are. - If a file/dir is already in the archive it will only be added at the - end of the archive. There is no update of the existing archived - file/dir. However while extracting the archive, the last file will - replace the first one. This results in a none optimization of the - archive size. - If a file/dir does not exist the file/dir is ignored. However an - error text is send to PEAR error. - If a file/dir is not readable the file/dir is ignored. However an - error text is send to PEAR error. - If the resulting filename/dirname (after the add/remove option or - not) string is greater than 99 char, the file/dir is - ignored. However an error text is send to PEAR error. -Arguments : - $p_filelist : An array of filenames and directory names, or a single - string with names separated by a single blank space. - $p_add_dir : A string which contains a path to be added to the - memorized path of each element in the list. - $p_remove_dir : A string which contains a path to be removed from - the memorized path of each element in the list, when - relevant. -Return value : - true on success, false on error. -Sample 1 : - $tar_object = new Archive_Tar("tarname.tar"); - [...] - $v_list[0]="dev/file.txt"; - $v_list[1]="dev/data/"; (Optional '/' at the end) - $v_list[2]="log/file.log"; - $tar_object->addModify($v_list, "install"); - // files are stored in the archive as : - // install/file.txt - // install/data - // install/data/file1.txt - // install/data/... all the files and sub-dirs of data/ - // install/file.log -Sample 2 : - $tar_object = new Archive_Tar("tarname.tar"); - [...] - $v_list[0]="dev/file.txt"; - $v_list[1]="dev/data/"; (Optional '/' at the end) - $v_list[2]="log/file.log"; - $tar_object->addModify($v_list, "install", "dev"); - // files are stored in the archive as : - // install/file.txt - // install/data - // install/data/file1.txt - // install/data/... all the files and sub-dirs of data/ - // install/log/file.log -How it works : - If the archive does not exists it create it and add the files. - If the archive does exists and is not compressed, it open it, jump - before the last empty 512 bytes block (tar footer) and add the files - at this point. - If the archive does exists and is compressed, a temporary copy file - is created. This temporary file is then 'gzip' read block by block - until the last empty block. The new files are then added in the - compressed file. - The adding of files is done by going through the file/dir list, - adding files per files, in a recursive way through the - directory. Each time a path need to be added/removed it is done - before writing the file header in the archive. - -Method : add($p_filelist) -Description : - This method add the files / directories listed in $p_filelist at the - end of the existing archive. If the archive does not yet exists it - is created. - The $p_filelist parameter can be an array of string, each string - representing a filename or a directory name with their path if - needed. It can also be a single string with names separated by a - single blank. - See addModify() method for details and limitations. -Arguments : - $p_filelist : An array of filenames and directory names, or a single - string with names separated by a single blank space. -Return value : - true on success, false on error. -Sample 1 : - $tar_object = new Archive_Tar("tarname.tar"); - [...] - $v_list[0]="dev/file.txt"; - $v_list[1]="dev/data/"; (Optional '/' at the end) - $v_list[2]="log/file.log"; - $tar_object->add($v_list); -Sample 2 : - $tar_object = new Archive_Tar("tarname.tgz", true); - [...] - $v_list[0]="dev/file.txt"; - $v_list[1]="dev/data/"; (Optional '/' at the end) - $v_list[2]="log/file.log"; - $tar_object->add($v_list); -How it works : - Simply call the addModify() method with the right parameters. - -Method : addString($p_filename, $p_string) -Description : - This method add a single string as a file at the - end of the existing archive. If the archive does not yet exists it - is created. -Arguments : - $p_filename : A string which contains the full filename path - that will be associated with the string. - $p_string : The content of the file added in the archive. -Return value : - true on success, false on error. -Sample 1 : - $v_archive = & new Archive_Tar($p_filename); - $v_archive->setErrorHandling(PEAR_ERROR_PRINT); - $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string'); - - -Method : extract($p_path = "") -Description : - This method extract all the content of the archive in the directory - indicated by $p_path.If $p_path is optional, if not set the archive - is extracted in the current directory. - While extracting a file, if the directory path does not exists it is - created. - See extractModify() for details and limitations. -Arguments : - $p_path : Optional path where the files/dir need to by extracted. -Return value : - true on success, false on error. -Sample : - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->extract(); -How it works : - Simply call the extractModify() method with appropriate parameters. - -Method : extractModify($p_path, $p_remove_path) -Description : - This method extract all the content of the archive in the directory - indicated by $p_path. When relevant the memorized path of the - files/dir can be modified by removing the $p_remove_path path at the - beginning of the file/dir path. - While extracting a file, if the directory path does not exists it is - created. - While extracting a file, if the file already exists it is replaced - without looking for last modification date. - While extracting a file, if the file already exists and is write - protected, the extraction is aborted. - While extracting a file, if a directory with the same name already - exists, the extraction is aborted. - While extracting a directory, if a file with the same name already - exists, the extraction is aborted. - While extracting a file/directory if the destination directory exist - and is write protected, or does not exist but can not be created, - the extraction is aborted. - If after extraction an extracted file does not show the correct - stored file size, the extraction is aborted. - When the extraction is aborted, a PEAR error text is set and false - is returned. However the result can be a partial extraction that may - need to be manually cleaned. -Arguments : - $p_path : The path of the directory where the files/dir need to by - extracted. - $p_remove_path : Part of the memorized path that can be removed if - present at the beginning of the file/dir path. -Return value : - true on success, false on error. -Sample : - // Imagine tarname.tar with files : - // dev/data/file.txt - // dev/data/log.txt - // readme.txt - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->extractModify("install", "dev"); - // Files will be extracted there : - // install/data/file.txt - // install/data/log.txt - // install/readme.txt -How it works : - Open the archive and call a more generic function that can extract - only a part of the archive or all the archive. - See extractList() method for more details. - -Method : extractInString($p_filename) -Description : - This method extract from the archive one file identified by $p_filename. - The return value is a string with the file content, or NULL on error. -Arguments : - $p_filename : The path of the file to extract in a string. -Return value : - a string with the file content or NULL. -Sample : - // Imagine tarname.tar with files : - // dev/data/file.txt - // dev/data/log.txt - // dev/readme.txt - $v_archive = & new Archive_Tar('tarname.tar'); - $v_archive->setErrorHandling(PEAR_ERROR_PRINT); - $v_string = $v_archive->extractInString('dev/readme.txt'); - echo $v_string; - -Method : listContent() -Description : - This method returns an array of arrays that describe each - file/directory present in the archive. - The array is not sorted, so it show the position of the file in the - archive. - The file informations are : - $file[filename] : Name and path of the file/dir. - $file[mode] : File permissions (result of fileperms()) - $file[uid] : user id - $file[gid] : group id - $file[size] : filesize - $file[mtime] : Last modification time (result of filemtime()) - $file[typeflag] : "" for file, "5" for directory -Arguments : -Return value : - An array of arrays or 0 on error. -Sample : - $tar_object = new Archive_Tar("tarname.tar"); - if (($v_list = $tar_object->listContent()) != 0) - for ($i=0; $i"; - echo " .size :'".$v_list[$i][size]."'
    "; - echo " .mtime :'".$v_list[$i][mtime]."' (". - date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")
    "; - echo " .mode :'".$v_list[$i][mode]."'
    "; - echo " .uid :'".$v_list[$i][uid]."'
    "; - echo " .gid :'".$v_list[$i][gid]."'
    "; - echo " .typeflag :'".$v_list[$i][typeflag]."'
    "; - } -How it works : - Call the same function as an extract however with a flag to only go - through the archive without extracting the files. - -Method : extractList($p_filelist, $p_path = "", $p_remove_path = "") -Description : - This method extract from the archive only the files indicated in the - $p_filelist. These files are extracted in the current directory or - in the directory indicated by the optional $p_path parameter. - If indicated the $p_remove_path can be used in the same way as it is - used in extractModify() method. -Arguments : - $p_filelist : An array of filenames and directory names, or a single - string with names separated by a single blank space. - $p_path : The path of the directory where the files/dir need to by - extracted. - $p_remove_path : Part of the memorized path that can be removed if - present at the beginning of the file/dir path. -Return value : - true on success, false on error. -Sample : - // Imagine tarname.tar with files : - // dev/data/file.txt - // dev/data/log.txt - // readme.txt - $tar_object = new Archive_Tar("tarname.tar"); - $tar_object->extractList("dev/data/file.txt readme.txt", "install", - "dev"); - // Files will be extracted there : - // install/data/file.txt - // install/readme.txt -How it works : - Go through the archive and extract only the files present in the - list. - -package.xml100664 764 764 11522 100664 6252 - - - Archive_Tar - Tar file management class - This class provides handling of tar files in PHP. -It supports creating, listing, extracting and adding to tar files. -Gzip support is available if PHP has the zlib extension built-in or -loaded. Bz2 compression is also supported with the bz2 extension loaded. - - - - cellog - Gregory Beaver - cellog@php.net - lead - - - vblavet - Vincent Blavet - vincent@phpconcept.net - lead - - - ssb - Stig Bakken - stig@php.net - helper - - - - 1.3.3 - 2009-03-27 - New BSD License - stable - minor bugfix release -* fix Bug #9921 compression with bzip2 fails [cellog] -* fix Bug #11594 _readLongHeader leaves 0 bytes in filename [jamessas] -* fix Bug #11769 Incorrect symlink handing [fajar99] - - - - - - - - - - - - - - - - - - - - - 1.3.3 - 2007-08-25 - PHP License - stable - - - 1.3.2 - 2007-01-03 - PHP License - stable - Correct Bug #4016 -Remove duplicate remove error display with '@' -Correct Bug #3909 : Check existence of OS_WINDOWS constant -Correct Bug #5452 fix for "lone zero block" when untarring packages -Change filemode (from pear-core/Archive/Tar.php v.1.21) -Correct Bug #6486 Can not extract symlinks -Correct Bug #6933 Archive_Tar (Tar file management class) Directory traversal -Correct Bug #8114 Files added on-the-fly not storing date -Correct Bug #9352 Bug on _dirCheck function over nfs path - - - - 1.3.1 - 2005-03-17 - PHP License - stable - Correct Bug #3855 - - - - 1.3.0 - 2005-03-06 - stable - Bugs correction (2475, 2488, 2135, 2176) - - - - 1.2 - 2004-05-08 - stable - Add support for other separator than the space char and bug - correction - - - - 1.1 - 2003-05-28 - stable - * Add support for BZ2 compression -* Add support for add and extract without using temporary files : methods addString() and extractInString() - - - - 1.0 - 2003-01-24 - stable - Change status to stable - - - - 0.10-b1 - 2003-01-08 - beta - Add support for long filenames (greater than 99 characters) - - - - 0.9 - 2002-05-27 - stable - Auto-detect gzip'ed files - - - - 0.4 - 2002-05-20 - stable - Windows bugfix: use forward slashes inside archives - - - - 0.2 - 2002-02-18 - stable - From initial commit to stable - - - - 0.3 - 2002-04-13 - stable - Windows bugfix: used wrong directory separators - - - - -package.xml100644 1750 1750 10425 10633574607 6452 - - Console_Getopt - pear.php.net - Command-line option parser - This is a PHP implementation of "getopt" supporting both -short and long options. - - Andrei Zmievski - andrei - andrei@php.net - yes - - - Stig Bakken - ssb - stig@php.net - no - - - Greg Beaver - cellog - cellog@php.net - yes - - 2007-06-12 - - - 1.2.3 - 1.2.1 - - - stable - stable - - PHP License - * fix Bug #11068: No way to read plain "-" option [cardoe] - - - - - - - PEAR - pear.php.net - 1.4.0 - 1.6.0 - - - - - 4.3.0 - - - 1.4.3 - - - - - - - - 1.2.2 - 1.2.1 - - - stable - stable - - 2007-02-17 - PHP License - * fix Bug #4475: An ambiguous error occurred when specifying similar longoption name. -* fix Bug #10055: Not failing properly on short options missing required values - - - - 1.2.1 - 1.2.1 - - - stable - stable - - 2006-12-08 - PHP License - Fixed bugs #4448 (Long parameter values truncated with longoption parameter) and #7444 (Trailing spaces after php closing tag) - - - - 1.2 - 1.2 - - - stable - stable - - 2003-12-11 - PHP License - Fix to preserve BC with 1.0 and allow correct behaviour for new users - - - - 1.0 - 1.0 - - - stable - stable - - 2002-09-13 - PHP License - Stable release - - - - 0.11 - 0.11 - - - beta - beta - - 2002-05-26 - PHP License - POSIX getopt compatibility fix: treat first element of args - array as command name - - - - 0.10 - 0.10 - - - beta - beta - - 2002-05-12 - PHP License - Packaging fix - - - - 0.9 - 0.9 - - - beta - beta - - 2002-05-12 - PHP License - Initial release - - - -Console_Getopt-1.2.3/Console/Getopt.php100644 1750 1750 25332 10633574607 13300 | -// +----------------------------------------------------------------------+ -// -// $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $ - -require_once 'PEAR.php'; - -/** - * Command-line options parsing class. - * - * @author Andrei Zmievski - * - */ -class Console_Getopt { - /** - * Parses the command-line options. - * - * The first parameter to this function should be the list of command-line - * arguments without the leading reference to the running program. - * - * The second parameter is a string of allowed short options. Each of the - * option letters can be followed by a colon ':' to specify that the option - * requires an argument, or a double colon '::' to specify that the option - * takes an optional argument. - * - * The third argument is an optional array of allowed long options. The - * leading '--' should not be included in the option name. Options that - * require an argument should be followed by '=', and options that take an - * option argument should be followed by '=='. - * - * The return value is an array of two elements: the list of parsed - * options and the list of non-option command-line arguments. Each entry in - * the list of parsed options is a pair of elements - the first one - * specifies the option, and the second one specifies the option argument, - * if there was one. - * - * Long and short options can be mixed. - * - * Most of the semantics of this function are based on GNU getopt_long(). - * - * @param array $args an array of command-line arguments - * @param string $short_options specifies the list of allowed short options - * @param array $long_options specifies the list of allowed long options - * - * @return array two-element array containing the list of parsed options and - * the non-option arguments - * - * @access public - * - */ - function getopt2($args, $short_options, $long_options = null) - { - return Console_Getopt::doGetopt(2, $args, $short_options, $long_options); - } - - /** - * This function expects $args to start with the script name (POSIX-style). - * Preserved for backwards compatibility. - * @see getopt2() - */ - function getopt($args, $short_options, $long_options = null) - { - return Console_Getopt::doGetopt(1, $args, $short_options, $long_options); - } - - /** - * The actual implementation of the argument parsing code. - */ - function doGetopt($version, $args, $short_options, $long_options = null) - { - // in case you pass directly readPHPArgv() as the first arg - if (PEAR::isError($args)) { - return $args; - } - if (empty($args)) { - return array(array(), array()); - } - $opts = array(); - $non_opts = array(); - - settype($args, 'array'); - - if ($long_options) { - sort($long_options); - } - - /* - * Preserve backwards compatibility with callers that relied on - * erroneous POSIX fix. - */ - if ($version < 2) { - if (isset($args[0]{0}) && $args[0]{0} != '-') { - array_shift($args); - } - } - - reset($args); - while (list($i, $arg) = each($args)) { - - /* The special element '--' means explicit end of - options. Treat the rest of the arguments as non-options - and end the loop. */ - if ($arg == '--') { - $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); - break; - } - - if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } elseif (strlen($arg) > 1 && $arg{1} == '-') { - $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); - if (PEAR::isError($error)) - return $error; - } elseif ($arg == '-') { - // - is stdin - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } else { - $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); - if (PEAR::isError($error)) - return $error; - } - } - - return array($opts, $non_opts); - } - - /** - * @access private - * - */ - function _parseShortOption($arg, $short_options, &$opts, &$args) - { - for ($i = 0; $i < strlen($arg); $i++) { - $opt = $arg{$i}; - $opt_arg = null; - - /* Try to find the short option in the specifier string. */ - if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') - { - return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt"); - } - - if (strlen($spec) > 1 && $spec{1} == ':') { - if (strlen($spec) > 2 && $spec{2} == ':') { - if ($i + 1 < strlen($arg)) { - /* Option takes an optional argument. Use the remainder of - the arg string if there is anything left. */ - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - } else { - /* Option requires an argument. Use the remainder of the arg - string if there is anything left. */ - if ($i + 1 < strlen($arg)) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } else if (list(, $opt_arg) = each($args)) { - /* Else use the next argument. */; - if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { - return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); - } - } else { - return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); - } - } - } - - $opts[] = array($opt, $opt_arg); - } - } - - /** - * @access private - * - */ - function _isShortOpt($arg) - { - return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]); - } - - /** - * @access private - * - */ - function _isLongOpt($arg) - { - return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && - preg_match('/[a-zA-Z]+$/', substr($arg, 2)); - } - - /** - * @access private - * - */ - function _parseLongOption($arg, $long_options, &$opts, &$args) - { - @list($opt, $opt_arg) = explode('=', $arg, 2); - $opt_len = strlen($opt); - - for ($i = 0; $i < count($long_options); $i++) { - $long_opt = $long_options[$i]; - $opt_start = substr($long_opt, 0, $opt_len); - $long_opt_name = str_replace('=', '', $long_opt); - - /* Option doesn't match. Go on to the next one. */ - if ($long_opt_name != $opt) { - continue; - } - - $opt_rest = substr($long_opt, $opt_len); - - /* Check that the options uniquely matches one of the allowed - options. */ - if ($i + 1 < count($long_options)) { - $next_option_rest = substr($long_options[$i + 1], $opt_len); - } else { - $next_option_rest = ''; - } - if ($opt_rest != '' && $opt{0} != '=' && - $i + 1 < count($long_options) && - $opt == substr($long_options[$i+1], 0, $opt_len) && - $next_option_rest != '' && - $next_option_rest{0} != '=') { - return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous"); - } - - if (substr($long_opt, -1) == '=') { - if (substr($long_opt, -2) != '==') { - /* Long option requires an argument. - Take the next argument if one wasn't specified. */; - if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { - return PEAR::raiseError("Console_Getopt: option --$opt requires an argument"); - } - if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { - return PEAR::raiseError("Console_Getopt: option requires an argument --$opt"); - } - } - } else if ($opt_arg) { - return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument"); - } - - $opts[] = array('--' . $opt, $opt_arg); - return; - } - - return PEAR::raiseError("Console_Getopt: unrecognized option --$opt"); - } - - /** - * Safely read the $argv PHP array across different PHP configurations. - * Will take care on register_globals and register_argc_argv ini directives - * - * @access public - * @return mixed the $argv PHP array or PEAR error if not registered - */ - function readPHPArgv() - { - global $argv; - if (!is_array($argv)) { - if (!@is_array($_SERVER['argv'])) { - if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { - return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)"); - } - return $GLOBALS['HTTP_SERVER_VARS']['argv']; - } - return $_SERVER['argv']; - } - return $argv; - } - -} - -?> -package2.xml100664 764 764 117255 100664 6366 - - PEAR - pear.php.net - PEAR Base System - The PEAR package contains: - * the PEAR installer, for creating, distributing - and installing packages - * the PEAR_Exception PHP5 error handling mechanism - * the PEAR_ErrorStack advanced error handling mechanism - * the PEAR_Error error handling mechanism - * the OS_Guess class for retrieving info about the OS - where PHP is running on - * the System class for quick handling of common operations - with files and directories - * the PEAR base class - Features in a nutshell: - * full support for channels - * pre-download dependency validation - * new package.xml 2.0 format allows tremendous flexibility while maintaining BC - * support for optional dependency groups and limited support for sub-packaging - * robust dependency support - * full dependency validation on uninstall - * remote install for hosts with only ftp access - no more problems with - restricted host installation - * full support for mirroring - * support for bundling several packages into a single tarball - * support for static dependencies on a url-based package - * support for custom file roles and installation tasks - - Greg Beaver - cellog - cellog@php.net - no - - - Pierre-Alain Joye - pajoye - pierre@php.net - no - - - Stig Bakken - ssb - stig@php.net - no - - - Tomas V.V.Cox - cox - cox@idecnet.com - no - - - Helgi Thormar - dufuz - dufuz@php.net - yes - - - Tias Guns - tias - tias@php.net - yes - - - Tim Jackson - timj - timj@php.net - no - - - Bertrand Gugger - toggg - toggg@php.net - no - - - Martin Jansen - mj - mj@php.net - no - - 2009-09-03 - - - 1.9.0 - 1.9.0 - - - stable - stable - - New BSD License - -* Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4.4.0 - 5.0 - 5.1.0 - 5.1.1 - 5.1.2 - 5.1.3 - 5.1.4 - 5.1.5 - - - 1.4.3 - - - Archive_Tar - pear.php.net - 1.1 - 1.3.3 - 1.3.0 - - - Structures_Graph - pear.php.net - 1.0.2 - 1.0.2 - - - Console_Getopt - pear.php.net - 1.2 - 1.2.3 - - - XML_Util - pear.php.net - 1.2.0 - 1.2.1 - - - PEAR_Frontend_Web - pear.php.net - 0.4 - - - - PEAR_Frontend_Gtk - pear.php.net - 0.4.0 - 0.4.0 - - - - xml - - - pcre - - - - - PEAR_Frontend_Web - pear.php.net - 0.5.1 - - - - - PEAR_Frontend_Gtk - pear.php.net - 0.4.0 - - - - - PEAR_Frontend_Gtk2 - pear.php.net - - - - - - - windows - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.8.0alpha1 - 1.8.0 - - - alpha - stable - - 2009-03-09 - New BSD License - -* Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] -* Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] -* Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] -* Implement Request #11170: script to generate Command/[command].xml [dufuz] -* Implement Request #11176: improve channel ... has updated its protocols message [dufuz] -* Implement Request #12706: pear list -a hard to read [dufuz] -* Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] -* Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] -* Implement Request #13927: install-pear.php should have option to set www_dir [timj] -* Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] -* Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. -* Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades -* Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] -* Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] - -* Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] -* Fix PHP Bug #47323: strotime warnings in make install [dufuz] - -* Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] -* Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] -* Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] -* Fix Bug #13953: config-set/config-show with channel alias fail [cellog] -* Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] -* Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] -* Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] -* Fix Bug #14210: pear list -ia brings warnings [dufuz] -* Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] -* Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] -* Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] -* Fix Bug #14437: openbasedir warning when loading config [dufuz] -* Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] -* Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] -* Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] -* Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] -* Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] -* Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] - -NOTE! -Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment -to migrate over to one of the alternatives that have ben provided: -* PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) -* PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) -* PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) -* PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) -* PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) -* PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) -* PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) -* PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) -* PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) -* PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) - -PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls -pear upgrade -f PEAR will allow people with lower versions -to upgrade to this release but no guarantees will be made that it will work properly. - -Support for XML RPC channels has been dropped - The only ones that used it -(pear.php.net and pecl.php.net) have used the REST interface for years now. -SOAP support also removed as it was only proof of concept. - -Move codebase from the PHP License to New BSD 2 clause license - - - - 2009-03-27 - - 1.8.0RC1 - 1.8.0 - - - beta - stable - - New BSD License - -* Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] -* Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] - -* Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] -* Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] - - - - 2009-04-10 - - 1.8.0 - 1.8.0 - - - stable - stable - - New BSD License - -Changes since RC1: - * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] - * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] - * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] - - Remove custom XML_Util class in favor of using upstream XML_Util package as dependency - -RC1 Release Notes: - * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] - * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] - - * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] - * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] - -Alpha1 Release Notes: - * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] - * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] - * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] - * Implement Request #11170: script to generate Command/[command].xml [dufuz] - * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] - * Implement Request #12706: pear list -a hard to read [dufuz] - * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] - * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] - * Implement Request #13927: install-pear.php should have option to set www_dir [timj] - * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] - * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. - * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades - * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] - * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] - - * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] - * Fix PHP Bug #47323: strotime warnings in make install [dufuz] - - * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] - * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] - * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] - * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] - * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] - * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] - * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] - * Fix Bug #14210: pear list -ia brings warnings [dufuz] - * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] - * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] - * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] - * Fix Bug #14437: openbasedir warning when loading config [dufuz] - * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] - * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] - * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] - * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] - * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] - * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] - - NOTE! - Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment - to migrate over to one of the alternatives that have ben provided: - * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) - * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) - * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) - * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) - * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) - * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) - * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) - * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) - * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) - * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) - - PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls - pear upgrade -f PEAR will allow people with lower versions - to upgrade to this release but no guarantees will be made that it will work properly. - - Support for XML RPC channels has been dropped - The only ones that used it - (pear.php.net and pecl.php.net) have used the REST interface for years now. - SOAP support also removed as it was only proof of concept. - - Move codebase from the PHP License to New BSD 2 clause license - - - - 2009-04-15 - - 1.8.1 - 1.8.1 - - - stable - stable - - New BSD License - -* Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz] - - - - 2009-08-18 - - 1.9.0RC1 - 1.9.0RC1 - - - beta - stable - - New BSD License - -* Implement Request #16213: add alias to list-channels output [dufuz] -* Implement Request #16378: pear svntag [dufuz] -* Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj] -* Implement Request #16396: package-dependencies should allow package names [dufuz] - -* Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz] -* Fix Bug #14493: pear install --offline doesn't print out errors [dufuz] -* Fix Bug #11348: pear package-dependencies isn't well explained [dufuz] -* Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz] -* Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz] -* Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz] -* Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz] -* Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj] -* Fix Bug #16444: Setting preferred mirror fails [dufuz] -* Fix the shutdown functions where a index might not exist and thus raise a notice [derick] - - - - 2009-08-20 - - 1.9.0RC2 - 1.9.0RC2 - - - beta - stable - - New BSD License - -* REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz] - - - - 2009-08-21 - - 1.9.0RC3 - 1.9.0RC3 - - - beta - stable - - New BSD License - -* Improved svntag support to handle packages like PEAR it self [dufuz] - - - - 2009-08-23 - - 1.9.0RC4 - 1.9.0RC4 - - - beta - stable - - New BSD License - -* Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz] -* Make sure channel aliases can't be made to start with - [dufuz] -* Output issues with pear search [dufuz] -* Fixed couple of stray notices [dufuz] - - - - 2009-09-03 - - 1.9.0 - 1.9.0 - - - stable - stable - - New BSD License - -* Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] - - - - -PEAR-1.9.0/OS/Guess.php100664 764 764 24634 100664 7457 - * @author Gregory Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Guess.php 278521 2009-04-09 22:24:12Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since PEAR 0.1 - */ - -// {{{ uname examples - -// php_uname() without args returns the same as 'uname -a', or a PHP-custom -// string for Windows. -// PHP versions prior to 4.3 return the uname of the host where PHP was built, -// as of 4.3 it returns the uname of the host running the PHP code. -// -// PC RedHat Linux 7.1: -// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown -// -// PC Debian Potato: -// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown -// -// PC FreeBSD 3.3: -// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386 -// -// PC FreeBSD 4.3: -// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386 -// -// PC FreeBSD 4.5: -// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386 -// -// PC FreeBSD 4.5 w/uname from GNU shellutils: -// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown -// -// HP 9000/712 HP-UX 10: -// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license -// -// HP 9000/712 HP-UX 10 w/uname from GNU shellutils: -// HP-UX host B.10.10 A 9000/712 unknown -// -// IBM RS6000/550 AIX 4.3: -// AIX host 3 4 000003531C00 -// -// AIX 4.3 w/uname from GNU shellutils: -// AIX host 3 4 000003531C00 unknown -// -// SGI Onyx IRIX 6.5 w/uname from GNU shellutils: -// IRIX64 host 6.5 01091820 IP19 mips -// -// SGI Onyx IRIX 6.5: -// IRIX64 host 6.5 01091820 IP19 -// -// SparcStation 20 Solaris 8 w/uname from GNU shellutils: -// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc -// -// SparcStation 20 Solaris 8: -// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20 -// -// Mac OS X (Darwin) -// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh -// -// Mac OS X early versions -// - -// }}} - -/* TODO: - * - define endianness, to allow matchSignature("bigend") etc. - */ - -/** - * Retrieves information about the current operating system - * - * This class uses php_uname() to grok information about the current OS - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Gregory Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class OS_Guess -{ - var $sysname; - var $nodename; - var $cpu; - var $release; - var $extra; - - function OS_Guess($uname = null) - { - list($this->sysname, - $this->release, - $this->cpu, - $this->extra, - $this->nodename) = $this->parseSignature($uname); - } - - function parseSignature($uname = null) - { - static $sysmap = array( - 'HP-UX' => 'hpux', - 'IRIX64' => 'irix', - ); - static $cpumap = array( - 'i586' => 'i386', - 'i686' => 'i386', - 'ppc' => 'powerpc', - ); - if ($uname === null) { - $uname = php_uname(); - } - $parts = preg_split('/\s+/', trim($uname)); - $n = count($parts); - - $release = $machine = $cpu = ''; - $sysname = $parts[0]; - $nodename = $parts[1]; - $cpu = $parts[$n-1]; - $extra = ''; - if ($cpu == 'unknown') { - $cpu = $parts[$n - 2]; - } - - switch ($sysname) { - case 'AIX' : - $release = "$parts[3].$parts[2]"; - break; - case 'Windows' : - switch ($parts[1]) { - case '95/98': - $release = '9x'; - break; - default: - $release = $parts[1]; - break; - } - $cpu = 'i386'; - break; - case 'Linux' : - $extra = $this->_detectGlibcVersion(); - // use only the first two digits from the kernel version - $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); - break; - case 'Mac' : - $sysname = 'darwin'; - $nodename = $parts[2]; - $release = $parts[3]; - if ($cpu == 'Macintosh') { - if ($parts[$n - 2] == 'Power') { - $cpu = 'powerpc'; - } - } - break; - case 'Darwin' : - if ($cpu == 'Macintosh') { - if ($parts[$n - 2] == 'Power') { - $cpu = 'powerpc'; - } - } - $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]); - break; - default: - $release = preg_replace('/-.*/', '', $parts[2]); - break; - } - - if (isset($sysmap[$sysname])) { - $sysname = $sysmap[$sysname]; - } else { - $sysname = strtolower($sysname); - } - if (isset($cpumap[$cpu])) { - $cpu = $cpumap[$cpu]; - } - return array($sysname, $release, $cpu, $extra, $nodename); - } - - function _detectGlibcVersion() - { - static $glibc = false; - if ($glibc !== false) { - return $glibc; // no need to run this multiple times - } - $major = $minor = 0; - include_once "System.php"; - // Use glibc's header file to - // get major and minor version number: - if (@file_exists('/usr/include/features.h') && - @is_readable('/usr/include/features.h')) { - if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) { - $features_file = fopen('/usr/include/features.h', 'rb'); - while (!feof($features_file)) { - $line = fgets($features_file, 8192); - if (!$line || (strpos($line, '#define') === false)) { - continue; - } - if (strpos($line, '__GLIBC__')) { - // major version number #define __GLIBC__ version - $line = preg_split('/\s+/', $line); - $glibc_major = trim($line[2]); - if (isset($glibc_minor)) { - break; - } - continue; - } - - if (strpos($line, '__GLIBC_MINOR__')) { - // got the minor version number - // #define __GLIBC_MINOR__ version - $line = preg_split('/\s+/', $line); - $glibc_minor = trim($line[2]); - if (isset($glibc_major)) { - break; - } - continue; - } - } - fclose($features_file); - if (!isset($glibc_major) || !isset($glibc_minor)) { - return $glibc = ''; - } - return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ; - } // no cpp - - $tmpfile = System::mktemp("glibctest"); - $fp = fopen($tmpfile, "w"); - fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n"); - fclose($fp); - $cpp = popen("/usr/bin/cpp $tmpfile", "r"); - while ($line = fgets($cpp, 1024)) { - if ($line{0} == '#' || trim($line) == '') { - continue; - } - - if (list($major, $minor) = explode(' ', trim($line))) { - break; - } - } - pclose($cpp); - unlink($tmpfile); - } // features.h - - if (!($major && $minor) && @is_link('/lib/libc.so.6')) { - // Let's try reading the libc.so.6 symlink - if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) { - list($major, $minor) = explode('.', $matches[1]); - } - } - - if (!($major && $minor)) { - return $glibc = ''; - } - - return $glibc = "glibc{$major}.{$minor}"; - } - - function getSignature() - { - if (empty($this->extra)) { - return "{$this->sysname}-{$this->release}-{$this->cpu}"; - } - return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}"; - } - - function getSysname() - { - return $this->sysname; - } - - function getNodename() - { - return $this->nodename; - } - - function getCpu() - { - return $this->cpu; - } - - function getRelease() - { - return $this->release; - } - - function getExtra() - { - return $this->extra; - } - - function matchSignature($match) - { - $fragments = is_array($match) ? $match : explode('-', $match); - $n = count($fragments); - $matches = 0; - if ($n > 0) { - $matches += $this->_matchFragment($fragments[0], $this->sysname); - } - if ($n > 1) { - $matches += $this->_matchFragment($fragments[1], $this->release); - } - if ($n > 2) { - $matches += $this->_matchFragment($fragments[2], $this->cpu); - } - if ($n > 3) { - $matches += $this->_matchFragment($fragments[3], $this->extra); - } - return ($matches == $n); - } - - function _matchFragment($fragment, $value) - { - if (strcspn($fragment, '*?') < strlen($fragment)) { - $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/'; - return preg_match($reg, $value); - } - return ($fragment == '*' || !strcasecmp($fragment, $value)); - } - -} -/* - * Local Variables: - * indent-tabs-mode: nil - * c-basic-offset: 4 - * End: - */PEAR-1.9.0/PEAR/ChannelFile/Parser.php100664 764 764 3362 100664 12156 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Parser.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base xml parser class - */ -require_once 'PEAR/XMLParser.php'; -require_once 'PEAR/ChannelFile.php'; -/** - * Parser for channel.xml - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_ChannelFile_Parser extends PEAR_XMLParser -{ - var $_config; - var $_logger; - var $_registry; - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - function parse($data, $file) - { - if (PEAR::isError($err = parent::parse($data, $file))) { - return $err; - } - - $ret = new PEAR_ChannelFile; - $ret->setConfig($this->_config); - if (isset($this->_logger)) { - $ret->setLogger($this->_logger); - } - - $ret->fromArray($this->_unserializedData); - // make sure the filelist is in the easy to read format needed - $ret->flattenFilelist(); - $ret->setPackagefile($file, $archive); - return $ret; - } -}PEAR-1.9.0/PEAR/Command/Auth.xml100664 764 764 2314 100664 11036 - - Connects and authenticates to remote server [Deprecated in favor of channel-login] - doLogin - li - - <channel name> -WARNING: This function is deprecated in favor of using channel-login - -Log in to a remote channel server. If <channel name> is not supplied, -the default channel is used. To use remote functions in the installer -that require any kind of privileges, you need to log in first. The -username and password you enter here will be stored in your per-user -PEAR configuration (~/.pearrc on Unix-like systems). After logging -in, your username and password will be sent along in subsequent -operations on the remote server. - - - Logs out from the remote server [Deprecated in favor of channel-logout] - doLogout - lo - - -WARNING: This function is deprecated in favor of using channel-logout - -Logs out from the remote server. This command does not actually -connect to the remote server, it only deletes the stored username and -password from your user configuration. - -PEAR-1.9.0/PEAR/Command/Auth.php100664 764 764 5136 100664 11032 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Auth.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - * @deprecated since 1.8.0alpha1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Channels.php'; - -/** - * PEAR commands for login/logout - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - * @deprecated since 1.8.0alpha1 - */ -class PEAR_Command_Auth extends PEAR_Command_Channels -{ - var $commands = array( - 'login' => array( - 'summary' => 'Connects and authenticates to remote server [Deprecated in favor of channel-login]', - 'shortcut' => 'li', - 'function' => 'doLogin', - 'options' => array(), - 'doc' => ' -WARNING: This function is deprecated in favor of using channel-login - -Log in to a remote channel server. If is not supplied, -the default channel is used. To use remote functions in the installer -that require any kind of privileges, you need to log in first. The -username and password you enter here will be stored in your per-user -PEAR configuration (~/.pearrc on Unix-like systems). After logging -in, your username and password will be sent along in subsequent -operations on the remote server.', - ), - 'logout' => array( - 'summary' => 'Logs out from the remote server [Deprecated in favor of channel-logout]', - 'shortcut' => 'lo', - 'function' => 'doLogout', - 'options' => array(), - 'doc' => ' -WARNING: This function is deprecated in favor of using channel-logout - -Logs out from the remote server. This command does not actually -connect to the remote server, it only deletes the stored username and -password from your user configuration.', - ) - - ); - - /** - * PEAR_Command_Auth constructor. - * - * @access public - */ - function PEAR_Command_Auth(&$ui, &$config) - { - parent::PEAR_Command_Channels($ui, $config); - } -}PEAR-1.9.0/PEAR/Command/Build.xml100664 764 764 404 100664 11152 - - Build an Extension From C Source - doBuild - b - - [package.xml] -Builds one or more extensions contained in a package. - -PEAR-1.9.0/PEAR/Command/Build.php100664 764 764 4453 100664 11171 - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Build.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for building extensions. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Build extends PEAR_Command_Common -{ - var $commands = array( - 'build' => array( - 'summary' => 'Build an Extension From C Source', - 'function' => 'doBuild', - 'shortcut' => 'b', - 'options' => array(), - 'doc' => '[package.xml] -Builds one or more extensions contained in a package.' - ), - ); - - /** - * PEAR_Command_Build constructor. - * - * @access public - */ - function PEAR_Command_Build(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function doBuild($command, $options, $params) - { - require_once 'PEAR/Builder.php'; - if (sizeof($params) < 1) { - $params[0] = 'package.xml'; - } - - $builder = &new PEAR_Builder($this->ui); - $this->debug = $this->config->get('verbose'); - $err = $builder->build($params[0], array(&$this, 'buildCallback')); - if (PEAR::isError($err)) { - return $err; - } - - return true; - } - - function buildCallback($what, $data) - { - if (($what == 'cmdoutput' && $this->debug > 1) || - ($what == 'output' && $this->debug > 0)) { - $this->ui->outputData(rtrim($data), 'build'); - } - } -}PEAR-1.9.0/PEAR/Command/Channels.xml100664 764 764 10172 100664 11711 - - List Available Channels - doList - lc - - -List all available channels for installation. - - - - Update the Channel List - doUpdateAll - uc - - -List all installed packages in all channels. - - - - Remove a Channel From the List - doDelete - cde - - <channel name> -Delete a channel from the registry. You may not -remove any channel that has installed packages. - - - - Add a Channel - doAdd - ca - - <channel.xml> -Add a private channel to the channel list. Note that all -public channels should be synced using "update-channels". -Parameter may be either a local file or remote URL to a -channel.xml. - - - - Update an Existing Channel - doUpdate - cu - - - f - will force download of new channel.xml if an existing channel name is used - - - c - will force download of new channel.xml if an existing channel name is used - CHANNEL - - - [<channel.xml>|<channel name>] -Update a channel in the channel list directly. Note that all -public channels can be synced using "update-channels". -Parameter may be a local or remote channel.xml, or the name of -an existing channel. - - - - Retrieve Information on a Channel - doInfo - ci - - <package> -List the files in an installed package. - - - - Specify an alias to a channel name - doAlias - cha - - <channel> <alias> -Specify a specific alias to use for a channel name. -The alias may not be an existing channel name or -alias. - - - - Initialize a Channel from its server - doDiscover - di - - [<channel.xml>|<channel name>] -Initialize a channel from its server and create a local channel.xml. -If <channel name> is in the format "<username>:<password>@<channel>" then -<username> and <password> will be set as the login username/password for -<channel>. Use caution when passing the username/password in this way, as -it may allow other users on your computer to briefly view your username/ -password via the system's process list. - - - - Connects and authenticates to remote channel server - doLogin - cli - - <channel name> -Log in to a remote channel server. If <channel name> is not supplied, -the default channel is used. To use remote functions in the installer -that require any kind of privileges, you need to log in first. The -username and password you enter here will be stored in your per-user -PEAR configuration (~/.pearrc on Unix-like systems). After logging -in, your username and password will be sent along in subsequent -operations on the remote server. - - - Logs out from the remote channel server - doLogout - clo - - <channel name> -Logs out from a remote channel server. If <channel name> is not supplied, -the default channel is used. This command does not actually connect to the -remote server, it only deletes the stored username and password from your user -configuration. - -PEAR-1.9.0/PEAR/Command/Channels.php100664 764 764 101377 100664 11730 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Channels.php 287561 2009-08-21 22:42:58Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -define('PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS', -500); - -/** - * PEAR commands for managing channels. - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Command_Channels extends PEAR_Command_Common -{ - var $commands = array( - 'list-channels' => array( - 'summary' => 'List Available Channels', - 'function' => 'doList', - 'shortcut' => 'lc', - 'options' => array(), - 'doc' => ' -List all available channels for installation. -', - ), - 'update-channels' => array( - 'summary' => 'Update the Channel List', - 'function' => 'doUpdateAll', - 'shortcut' => 'uc', - 'options' => array(), - 'doc' => ' -List all installed packages in all channels. -' - ), - 'channel-delete' => array( - 'summary' => 'Remove a Channel From the List', - 'function' => 'doDelete', - 'shortcut' => 'cde', - 'options' => array(), - 'doc' => ' -Delete a channel from the registry. You may not -remove any channel that has installed packages. -' - ), - 'channel-add' => array( - 'summary' => 'Add a Channel', - 'function' => 'doAdd', - 'shortcut' => 'ca', - 'options' => array(), - 'doc' => ' -Add a private channel to the channel list. Note that all -public channels should be synced using "update-channels". -Parameter may be either a local file or remote URL to a -channel.xml. -' - ), - 'channel-update' => array( - 'summary' => 'Update an Existing Channel', - 'function' => 'doUpdate', - 'shortcut' => 'cu', - 'options' => array( - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'will force download of new channel.xml if an existing channel name is used', - ), - 'channel' => array( - 'shortopt' => 'c', - 'arg' => 'CHANNEL', - 'doc' => 'will force download of new channel.xml if an existing channel name is used', - ), -), - 'doc' => '[|] -Update a channel in the channel list directly. Note that all -public channels can be synced using "update-channels". -Parameter may be a local or remote channel.xml, or the name of -an existing channel. -' - ), - 'channel-info' => array( - 'summary' => 'Retrieve Information on a Channel', - 'function' => 'doInfo', - 'shortcut' => 'ci', - 'options' => array(), - 'doc' => ' -List the files in an installed package. -' - ), - 'channel-alias' => array( - 'summary' => 'Specify an alias to a channel name', - 'function' => 'doAlias', - 'shortcut' => 'cha', - 'options' => array(), - 'doc' => ' -Specify a specific alias to use for a channel name. -The alias may not be an existing channel name or -alias. -' - ), - 'channel-discover' => array( - 'summary' => 'Initialize a Channel from its server', - 'function' => 'doDiscover', - 'shortcut' => 'di', - 'options' => array(), - 'doc' => '[|] -Initialize a channel from its server and create a local channel.xml. -If is in the format ":@" then - and will be set as the login username/password for -. Use caution when passing the username/password in this way, as -it may allow other users on your computer to briefly view your username/ -password via the system\'s process list. -' - ), - 'channel-login' => array( - 'summary' => 'Connects and authenticates to remote channel server', - 'shortcut' => 'cli', - 'function' => 'doLogin', - 'options' => array(), - 'doc' => ' -Log in to a remote channel server. If is not supplied, -the default channel is used. To use remote functions in the installer -that require any kind of privileges, you need to log in first. The -username and password you enter here will be stored in your per-user -PEAR configuration (~/.pearrc on Unix-like systems). After logging -in, your username and password will be sent along in subsequent -operations on the remote server.', - ), - 'channel-logout' => array( - 'summary' => 'Logs out from the remote channel server', - 'shortcut' => 'clo', - 'function' => 'doLogout', - 'options' => array(), - 'doc' => ' -Logs out from a remote channel server. If is not supplied, -the default channel is used. This command does not actually connect to the -remote server, it only deletes the stored username and password from your user -configuration.', - ), - ); - - /** - * PEAR_Command_Registry constructor. - * - * @access public - */ - function PEAR_Command_Channels(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function _sortChannels($a, $b) - { - return strnatcasecmp($a->getName(), $b->getName()); - } - - function doList($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - $registered = $reg->getChannels(); - usort($registered, array(&$this, '_sortchannels')); - $i = $j = 0; - $data = array( - 'caption' => 'Registered Channels:', - 'border' => true, - 'headline' => array('Channel', 'Alias', 'Summary') - ); - foreach ($registered as $channel) { - $data['data'][] = array($channel->getName(), - $channel->getAlias(), - $channel->getSummary()); - } - - if (count($registered) === 0) { - $data = '(no registered channels)'; - } - $this->ui->outputData($data, $command); - return true; - } - - function doUpdateAll($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - $channels = $reg->getChannels(); - - $success = true; - foreach ($channels as $channel) { - if ($channel->getName() != '__uri') { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->doUpdate('channel-update', - $options, - array($channel->getName())); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - $success = false; - } else { - $success &= $err; - } - } - } - return $success; - } - - function doInfo($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError("No channel specified"); - } - - $reg = &$this->config->getRegistry(); - $channel = strtolower($params[0]); - if ($reg->channelExists($channel)) { - $chan = $reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); - } - } else { - if (strpos($channel, '://')) { - $downloader = &$this->getDownloader(); - $tmpdir = $this->config->get('temp_dir'); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($loc)) { - return $this->raiseError('Cannot open "' . $channel . - '" (' . $loc->getMessage() . ')'); - } else { - $contents = implode('', file($loc)); - } - } else { - if (!file_exists($params[0])) { - return $this->raiseError('Unknown channel "' . $channel . '"'); - } - - $fp = fopen($params[0], 'r'); - if (!$fp) { - return $this->raiseError('Cannot open "' . $params[0] . '"'); - } - - $contents = ''; - while (!feof($fp)) { - $contents .= fread($fp, 1024); - } - fclose($fp); - } - - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $chan = new PEAR_ChannelFile; - $chan->fromXmlString($contents); - $chan->validate(); - if ($errs = $chan->getErrors(true)) { - foreach ($errs as $err) { - $this->ui->outputData($err['level'] . ': ' . $err['message']); - } - return $this->raiseError('Channel file "' . $params[0] . '" is not valid'); - } - } - - if (!$chan) { - return $this->raiseError('Serious error: Channel "' . $params[0] . - '" has a corrupted registry entry'); - } - - $channel = $chan->getName(); - $caption = 'Channel ' . $channel . ' Information:'; - $data1 = array( - 'caption' => $caption, - 'border' => true); - $data1['data']['server'] = array('Name and Server', $chan->getName()); - if ($chan->getAlias() != $chan->getName()) { - $data1['data']['alias'] = array('Alias', $chan->getAlias()); - } - - $data1['data']['summary'] = array('Summary', $chan->getSummary()); - $validate = $chan->getValidationPackage(); - $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']); - $data1['data']['vpackageversion'] = - array('Validation Package Version', $validate['attribs']['version']); - $d = array(); - $d['main'] = $data1; - - $data['data'] = array(); - $data['caption'] = 'Server Capabilities'; - $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base'); - if ($chan->supportsREST()) { - if ($chan->supportsREST()) { - $funcs = $chan->getFunctions('rest'); - if (!isset($funcs[0])) { - $funcs = array($funcs); - } - foreach ($funcs as $protocol) { - $data['data'][] = array('rest', $protocol['attribs']['type'], - $protocol['_content']); - } - } - } else { - $data['data'][] = array('No supported protocols'); - } - - $d['protocols'] = $data; - $data['data'] = array(); - $mirrors = $chan->getMirrors(); - if ($mirrors) { - $data['caption'] = 'Channel ' . $channel . ' Mirrors:'; - unset($data['headline']); - foreach ($mirrors as $mirror) { - $data['data'][] = array($mirror['attribs']['host']); - $d['mirrors'] = $data; - } - - foreach ($mirrors as $i => $mirror) { - $data['data'] = array(); - $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities'; - $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base'); - if ($chan->supportsREST($mirror['attribs']['host'])) { - if ($chan->supportsREST($mirror['attribs']['host'])) { - $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']); - if (!isset($funcs[0])) { - $funcs = array($funcs); - } - - foreach ($funcs as $protocol) { - $data['data'][] = array('rest', $protocol['attribs']['type'], - $protocol['_content']); - } - } - } else { - $data['data'][] = array('No supported protocols'); - } - $d['mirrorprotocols' . $i] = $data; - } - } - $this->ui->outputData($d, 'channel-info'); - } - - // }}} - - function doDelete($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError('channel-delete: no channel specified'); - } - - $reg = &$this->config->getRegistry(); - if (!$reg->channelExists($params[0])) { - return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist'); - } - - $channel = $reg->channelName($params[0]); - if ($channel == 'pear.php.net') { - return $this->raiseError('Cannot delete the pear.php.net channel'); - } - - if ($channel == 'pecl.php.net') { - return $this->raiseError('Cannot delete the pecl.php.net channel'); - } - - if ($channel == 'doc.php.net') { - return $this->raiseError('Cannot delete the doc.php.net channel'); - } - - if ($channel == '__uri') { - return $this->raiseError('Cannot delete the __uri pseudo-channel'); - } - - if (PEAR::isError($err = $reg->listPackages($channel))) { - return $err; - } - - if (count($err)) { - return $this->raiseError('Channel "' . $channel . - '" has installed packages, cannot delete'); - } - - if (!$reg->deleteChannel($channel)) { - return $this->raiseError('Channel "' . $channel . '" deletion failed'); - } else { - $this->config->deleteChannel($channel); - $this->ui->outputData('Channel "' . $channel . '" deleted', $command); - } - } - - function doAdd($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError('channel-add: no channel file specified'); - } - - if (strpos($params[0], '://')) { - $downloader = &$this->getDownloader(); - $tmpdir = $this->config->get('temp_dir'); - if (!file_exists($tmpdir)) { - require_once 'System.php'; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = System::mkdir(array('-p', $tmpdir)); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($err)) { - return $this->raiseError('channel-add: temp_dir does not exist: "' . - $tmpdir . - '" - You can change this location with "pear config-set temp_dir"'); - } - } - - if (!is_writable($tmpdir)) { - return $this->raiseError('channel-add: temp_dir is not writable: "' . - $tmpdir . - '" - You can change this location with "pear config-set temp_dir"'); - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($loc)) { - return $this->raiseError('channel-add: Cannot open "' . $params[0] . - '" (' . $loc->getMessage() . ')'); - } - - list($loc, $lastmodified) = $loc; - $contents = implode('', file($loc)); - } else { - $lastmodified = $fp = false; - if (file_exists($params[0])) { - $fp = fopen($params[0], 'r'); - } - - if (!$fp) { - return $this->raiseError('channel-add: cannot open "' . $params[0] . '"'); - } - - $contents = ''; - while (!feof($fp)) { - $contents .= fread($fp, 1024); - } - fclose($fp); - } - - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $channel = new PEAR_ChannelFile; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $result = $channel->fromXmlString($contents); - PEAR::staticPopErrorHandling(); - if (!$result) { - $exit = false; - if (count($errors = $channel->getErrors(true))) { - foreach ($errors as $error) { - $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message'])); - if (!$exit) { - $exit = $error['level'] == 'error' ? true : false; - } - } - if ($exit) { - return $this->raiseError('channel-add: invalid channel.xml file'); - } - } - } - - $reg = &$this->config->getRegistry(); - if ($reg->channelExists($channel->getName())) { - return $this->raiseError('channel-add: Channel "' . $channel->getName() . - '" exists, use channel-update to update entry', PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS); - } - - $ret = $reg->addChannel($channel, $lastmodified); - if (PEAR::isError($ret)) { - return $ret; - } - - if (!$ret) { - return $this->raiseError('channel-add: adding Channel "' . $channel->getName() . - '" to registry failed'); - } - - $this->config->setChannels($reg->listChannels()); - $this->config->writeConfigFile(); - $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command); - } - - function doUpdate($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError("No channel file specified"); - } - - $tmpdir = $this->config->get('temp_dir'); - if (!file_exists($tmpdir)) { - require_once 'System.php'; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = System::mkdir(array('-p', $tmpdir)); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($err)) { - return $this->raiseError('channel-add: temp_dir does not exist: "' . - $tmpdir . - '" - You can change this location with "pear config-set temp_dir"'); - } - } - - if (!is_writable($tmpdir)) { - return $this->raiseError('channel-add: temp_dir is not writable: "' . - $tmpdir . - '" - You can change this location with "pear config-set temp_dir"'); - } - - $reg = &$this->config->getRegistry(); - $lastmodified = false; - if ((!file_exists($params[0]) || is_dir($params[0])) - && $reg->channelExists(strtolower($params[0]))) { - $c = $reg->getChannel(strtolower($params[0])); - if (PEAR::isError($c)) { - return $this->raiseError($c); - } - - $this->ui->outputData("Updating channel \"$params[0]\"", $command); - $dl = &$this->getDownloader(array()); - // if force is specified, use a timestamp of "1" to force retrieval - $lastmodified = isset($options['force']) ? false : $c->lastModified(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml', - $this->ui, $tmpdir, null, $lastmodified); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($contents)) { - // Attempt to fall back to https - $this->ui->outputData("Channel \"$params[0]\" is not responding over http://, failed with message: " . $contents->getMessage()); - $this->ui->outputData("Trying channel \"$params[0]\" over https:// instead"); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $contents = $dl->downloadHttp('https://' . $c->getName() . '/channel.xml', - $this->ui, $tmpdir, null, $lastmodified); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($contents)) { - return $this->raiseError('Cannot retrieve channel.xml for channel "' . - $c->getName() . '" (' . $contents->getMessage() . ')'); - } - } - - list($contents, $lastmodified) = $contents; - if (!$contents) { - $this->ui->outputData("Channel \"$params[0]\" is up to date"); - return; - } - - $contents = implode('', file($contents)); - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $channel = new PEAR_ChannelFile; - $channel->fromXmlString($contents); - if (!$channel->getErrors()) { - // security check: is the downloaded file for the channel we got it from? - if (strtolower($channel->getName()) != strtolower($c->getName())) { - if (!isset($options['force'])) { - return $this->raiseError('ERROR: downloaded channel definition file' . - ' for channel "' . $channel->getName() . '" from channel "' . - strtolower($c->getName()) . '"'); - } - - $this->ui->log(0, 'WARNING: downloaded channel definition file' . - ' for channel "' . $channel->getName() . '" from channel "' . - strtolower($c->getName()) . '"'); - } - } - } else { - if (strpos($params[0], '://')) { - $dl = &$this->getDownloader(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $loc = $dl->downloadHttp($params[0], - $this->ui, $tmpdir, null, $lastmodified); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($loc)) { - return $this->raiseError("Cannot open " . $params[0] . - ' (' . $loc->getMessage() . ')'); - } - - list($loc, $lastmodified) = $loc; - $contents = implode('', file($loc)); - } else { - $fp = false; - if (file_exists($params[0])) { - $fp = fopen($params[0], 'r'); - } - - if (!$fp) { - return $this->raiseError("Cannot open " . $params[0]); - } - - $contents = ''; - while (!feof($fp)) { - $contents .= fread($fp, 1024); - } - fclose($fp); - } - - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $channel = new PEAR_ChannelFile; - $channel->fromXmlString($contents); - } - - $exit = false; - if (count($errors = $channel->getErrors(true))) { - foreach ($errors as $error) { - $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message'])); - if (!$exit) { - $exit = $error['level'] == 'error' ? true : false; - } - } - if ($exit) { - return $this->raiseError('Invalid channel.xml file'); - } - } - - if (!$reg->channelExists($channel->getName())) { - return $this->raiseError('Error: Channel "' . $channel->getName() . - '" does not exist, use channel-add to add an entry'); - } - - $ret = $reg->updateChannel($channel, $lastmodified); - if (PEAR::isError($ret)) { - return $ret; - } - - if (!$ret) { - return $this->raiseError('Updating Channel "' . $channel->getName() . - '" in registry failed'); - } - - $this->config->setChannels($reg->listChannels()); - $this->config->writeConfigFile(); - $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded'); - } - - function &getDownloader() - { - if (!class_exists('PEAR_Downloader')) { - require_once 'PEAR/Downloader.php'; - } - $a = new PEAR_Downloader($this->ui, array(), $this->config); - return $a; - } - - function doAlias($command, $options, $params) - { - if (count($params) === 1) { - return $this->raiseError('No channel alias specified'); - } - - if (count($params) !== 2 || (!empty($params[1]) && $params[1]{0} == '-')) { - return $this->raiseError( - 'Invalid format, correct is: channel-alias channel alias'); - } - - $reg = &$this->config->getRegistry(); - if (!$reg->channelExists($params[0], true)) { - $extra = ''; - if ($reg->isAlias($params[0])) { - $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' . - strtolower($params[1]) . '")'; - } - - return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra); - } - - if ($reg->isAlias($params[1])) { - return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' . - 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias'); - } - - $chan = &$reg->getChannel($params[0]); - if (PEAR::isError($chan)) { - return $this->raiseError('Corrupt registry? Error retrieving channel "' . $params[0] . - '" information (' . $chan->getMessage() . ')'); - } - - // make it a local alias - if (!$chan->setAlias(strtolower($params[1]), true)) { - return $this->raiseError('Alias "' . strtolower($params[1]) . - '" is not a valid channel alias'); - } - - $reg->updateChannel($chan); - $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' . - strtolower($params[1]) . '"'); - } - - /** - * The channel-discover command - * - * @param string $command command name - * @param array $options option_name => value - * @param array $params list of additional parameters. - * $params[0] should contain a string with either: - * - or - * - :@ - * @return null|PEAR_Error - */ - function doDiscover($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError("No channel server specified"); - } - - // Look for the possible input format ":@" - if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) { - $username = $matches[1]; - $password = $matches[2]; - $channel = $matches[3]; - } else { - $channel = $params[0]; - } - - $reg = &$this->config->getRegistry(); - if ($reg->channelExists($channel)) { - if (!$reg->isAlias($channel)) { - return $this->raiseError("Channel \"$channel\" is already initialized", PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS); - } - - return $this->raiseError("A channel alias named \"$channel\" " . - 'already exists, aliasing channel "' . $reg->channelName($channel) - . '"'); - } - - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml')); - $this->popErrorHandling(); - if (PEAR::isError($err)) { - if ($err->getCode() === PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS) { - return $this->raiseError("Discovery of channel \"$channel\" failed (" . - $err->getMessage() . ')'); - } - // Attempt fetch via https - $this->ui->outputData("Discovering channel $channel over http:// failed with message: " . $err->getMessage()); - $this->ui->outputData("Trying to discover channel $channel over https:// instead"); - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->doAdd($command, $options, array('https://' . $channel . '/channel.xml')); - $this->popErrorHandling(); - if (PEAR::isError($err)) { - return $this->raiseError("Discovery of channel \"$channel\" failed (" . - $err->getMessage() . ')'); - } - } - - // Store username/password if they were given - // Arguably we should do a logintest on the channel here, but since - // that's awkward on a REST-based channel (even "pear login" doesn't - // do it for those), and XML-RPC is deprecated, it's fairly pointless. - if (isset($username)) { - $this->config->set('username', $username, 'user', $channel); - $this->config->set('password', $password, 'user', $channel); - $this->config->store(); - $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command); - } - - $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command); - } - - /** - * Execute the 'login' command. - * - * @param string $command command name - * @param array $options option_name => value - * @param array $params list of additional parameters - * - * @return bool TRUE on success or - * a PEAR error on failure - * - * @access public - */ - function doLogin($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - - // If a parameter is supplied, use that as the channel to log in to - $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel'); - - $chan = $reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); - } - - $server = $this->config->get('preferred_mirror', null, $channel); - $username = $this->config->get('username', null, $channel); - if (empty($username)) { - $username = isset($_ENV['USER']) ? $_ENV['USER'] : null; - } - $this->ui->outputData("Logging in to $server.", $command); - - list($username, $password) = $this->ui->userDialog( - $command, - array('Username', 'Password'), - array('text', 'password'), - array($username, '') - ); - $username = trim($username); - $password = trim($password); - - $ourfile = $this->config->getConfFile('user'); - if (!$ourfile) { - $ourfile = $this->config->getConfFile('system'); - } - - $this->config->set('username', $username, 'user', $channel); - $this->config->set('password', $password, 'user', $channel); - - if ($chan->supportsREST()) { - $ok = true; - } - - if ($ok !== true) { - return $this->raiseError('Login failed!'); - } - - $this->ui->outputData("Logged in.", $command); - // avoid changing any temporary settings changed with -d - $ourconfig = new PEAR_Config($ourfile, $ourfile); - $ourconfig->set('username', $username, 'user', $channel); - $ourconfig->set('password', $password, 'user', $channel); - $ourconfig->store(); - - return true; - } - - /** - * Execute the 'logout' command. - * - * @param string $command command name - * @param array $options option_name => value - * @param array $params list of additional parameters - * - * @return bool TRUE on success or - * a PEAR error on failure - * - * @access public - */ - function doLogout($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - - // If a parameter is supplied, use that as the channel to log in to - $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel'); - - $chan = $reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); - } - - $server = $this->config->get('preferred_mirror', null, $channel); - $this->ui->outputData("Logging out from $server.", $command); - $this->config->remove('username', 'user', $channel); - $this->config->remove('password', 'user', $channel); - $this->config->store(); - return true; - } -}PEAR-1.9.0/PEAR/Command/Common.php100664 764 764 20144 100664 11375 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR.php'; - -/** - * PEAR commands base class - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Common extends PEAR -{ - /** - * PEAR_Config object used to pass user system and configuration - * on when executing commands - * - * @var PEAR_Config - */ - var $config; - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * User Interface object, for all interaction with the user. - * @var object - */ - var $ui; - - var $_deps_rel_trans = array( - 'lt' => '<', - 'le' => '<=', - 'eq' => '=', - 'ne' => '!=', - 'gt' => '>', - 'ge' => '>=', - 'has' => '==' - ); - - var $_deps_type_trans = array( - 'pkg' => 'package', - 'ext' => 'extension', - 'php' => 'PHP', - 'prog' => 'external program', - 'ldlib' => 'external library for linking', - 'rtlib' => 'external runtime library', - 'os' => 'operating system', - 'websrv' => 'web server', - 'sapi' => 'SAPI backend' - ); - - /** - * PEAR_Command_Common constructor. - * - * @access public - */ - function PEAR_Command_Common(&$ui, &$config) - { - parent::PEAR(); - $this->config = &$config; - $this->ui = &$ui; - } - - /** - * Return a list of all the commands defined by this class. - * @return array list of commands - * @access public - */ - function getCommands() - { - $ret = array(); - foreach (array_keys($this->commands) as $command) { - $ret[$command] = $this->commands[$command]['summary']; - } - - return $ret; - } - - /** - * Return a list of all the command shortcuts defined by this class. - * @return array shortcut => command - * @access public - */ - function getShortcuts() - { - $ret = array(); - foreach (array_keys($this->commands) as $command) { - if (isset($this->commands[$command]['shortcut'])) { - $ret[$this->commands[$command]['shortcut']] = $command; - } - } - - return $ret; - } - - function getOptions($command) - { - $shortcuts = $this->getShortcuts(); - if (isset($shortcuts[$command])) { - $command = $shortcuts[$command]; - } - - if (isset($this->commands[$command]) && - isset($this->commands[$command]['options'])) { - return $this->commands[$command]['options']; - } - - return null; - } - - function getGetoptArgs($command, &$short_args, &$long_args) - { - $short_args = ''; - $long_args = array(); - if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) { - return; - } - - reset($this->commands[$command]['options']); - while (list($option, $info) = each($this->commands[$command]['options'])) { - $larg = $sarg = ''; - if (isset($info['arg'])) { - if ($info['arg']{0} == '(') { - $larg = '=='; - $sarg = '::'; - $arg = substr($info['arg'], 1, -1); - } else { - $larg = '='; - $sarg = ':'; - $arg = $info['arg']; - } - } - - if (isset($info['shortopt'])) { - $short_args .= $info['shortopt'] . $sarg; - } - - $long_args[] = $option . $larg; - } - } - - /** - * Returns the help message for the given command - * - * @param string $command The command - * @return mixed A fail string if the command does not have help or - * a two elements array containing [0]=>help string, - * [1]=> help string for the accepted cmd args - */ - function getHelp($command) - { - $config = &PEAR_Config::singleton(); - if (!isset($this->commands[$command])) { - return "No such command \"$command\""; - } - - $help = null; - if (isset($this->commands[$command]['doc'])) { - $help = $this->commands[$command]['doc']; - } - - if (empty($help)) { - // XXX (cox) Fallback to summary if there is no doc (show both?) - if (!isset($this->commands[$command]['summary'])) { - return "No help for command \"$command\""; - } - $help = $this->commands[$command]['summary']; - } - - if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { - foreach($matches[0] as $k => $v) { - $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); - } - } - - return array($help, $this->getHelpArgs($command)); - } - - /** - * Returns the help for the accepted arguments of a command - * - * @param string $command - * @return string The help string - */ - function getHelpArgs($command) - { - if (isset($this->commands[$command]['options']) && - count($this->commands[$command]['options'])) - { - $help = "Options:\n"; - foreach ($this->commands[$command]['options'] as $k => $v) { - if (isset($v['arg'])) { - if ($v['arg'][0] == '(') { - $arg = substr($v['arg'], 1, -1); - $sapp = " [$arg]"; - $lapp = "[=$arg]"; - } else { - $sapp = " $v[arg]"; - $lapp = "=$v[arg]"; - } - } else { - $sapp = $lapp = ""; - } - - if (isset($v['shortopt'])) { - $s = $v['shortopt']; - $help .= " -$s$sapp, --$k$lapp\n"; - } else { - $help .= " --$k$lapp\n"; - } - - $p = " "; - $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); - $help .= " $doc\n"; - } - - return $help; - } - - return null; - } - - function run($command, $options, $params) - { - if (empty($this->commands[$command]['function'])) { - // look for shortcuts - foreach (array_keys($this->commands) as $cmd) { - if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) { - if (empty($this->commands[$cmd]['function'])) { - return $this->raiseError("unknown command `$command'"); - } else { - $func = $this->commands[$cmd]['function']; - } - $command = $cmd; - - //$command = $this->commands[$cmd]['function']; - break; - } - } - } else { - $func = $this->commands[$command]['function']; - } - - return $this->$func($command, $options, $params); - } -}PEAR-1.9.0/PEAR/Command/Config.xml100664 764 764 6466 100664 11356 - - Show All Settings - doConfigShow - csh - - - c - show configuration variables for another channel - CHAN - - - [layer] -Displays all configuration values. An optional argument -may be used to tell which configuration layer to display. Valid -configuration layers are "user", "system" and "default". To display -configurations for different channels, set the default_channel -configuration variable and run config-show again. - - - - Show One Setting - doConfigGet - cg - - - c - show configuration variables for another channel - CHAN - - - <parameter> [layer] -Displays the value of one configuration parameter. The -first argument is the name of the parameter, an optional second argument -may be used to tell which configuration layer to look in. Valid configuration -layers are "user", "system" and "default". If no layer is specified, a value -will be picked from the first layer that defines the parameter, in the order -just specified. The configuration value will be retrieved for the channel -specified by the default_channel configuration variable. - - - - Change Setting - doConfigSet - cs - - - c - show configuration variables for another channel - CHAN - - - <parameter> <value> [layer] -Sets the value of one configuration parameter. The first argument is -the name of the parameter, the second argument is the new value. Some -parameters are subject to validation, and the command will fail with -an error message if the new value does not make sense. An optional -third argument may be used to specify in which layer to set the -configuration parameter. The default layer is "user". The -configuration value will be set for the current channel, which -is controlled by the default_channel configuration variable. - - - - Show Information About Setting - doConfigHelp - ch - - [parameter] -Displays help for a configuration parameter. Without arguments it -displays help for all configuration parameters. - - - - Create a Default configuration file - doConfigCreate - coc - - - w - create a config file for a windows install - - - <root path> <filename> -Create a default configuration file with all directory configuration -variables set to subdirectories of <root path>, and save it as <filename>. -This is useful especially for creating a configuration file for a remote -PEAR installation (using the --remoteconfig option of install, upgrade, -and uninstall). - - -PEAR-1.9.0/PEAR/Command/Config.php100664 764 764 36076 100664 11365 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Config.php 287554 2009-08-21 21:16:25Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for managing configuration data. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Config extends PEAR_Command_Common -{ - var $commands = array( - 'config-show' => array( - 'summary' => 'Show All Settings', - 'function' => 'doConfigShow', - 'shortcut' => 'csh', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'show configuration variables for another channel', - 'arg' => 'CHAN', - ), -), - 'doc' => '[layer] -Displays all configuration values. An optional argument -may be used to tell which configuration layer to display. Valid -configuration layers are "user", "system" and "default". To display -configurations for different channels, set the default_channel -configuration variable and run config-show again. -', - ), - 'config-get' => array( - 'summary' => 'Show One Setting', - 'function' => 'doConfigGet', - 'shortcut' => 'cg', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'show configuration variables for another channel', - 'arg' => 'CHAN', - ), -), - 'doc' => ' [layer] -Displays the value of one configuration parameter. The -first argument is the name of the parameter, an optional second argument -may be used to tell which configuration layer to look in. Valid configuration -layers are "user", "system" and "default". If no layer is specified, a value -will be picked from the first layer that defines the parameter, in the order -just specified. The configuration value will be retrieved for the channel -specified by the default_channel configuration variable. -', - ), - 'config-set' => array( - 'summary' => 'Change Setting', - 'function' => 'doConfigSet', - 'shortcut' => 'cs', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'show configuration variables for another channel', - 'arg' => 'CHAN', - ), -), - 'doc' => ' [layer] -Sets the value of one configuration parameter. The first argument is -the name of the parameter, the second argument is the new value. Some -parameters are subject to validation, and the command will fail with -an error message if the new value does not make sense. An optional -third argument may be used to specify in which layer to set the -configuration parameter. The default layer is "user". The -configuration value will be set for the current channel, which -is controlled by the default_channel configuration variable. -', - ), - 'config-help' => array( - 'summary' => 'Show Information About Setting', - 'function' => 'doConfigHelp', - 'shortcut' => 'ch', - 'options' => array(), - 'doc' => '[parameter] -Displays help for a configuration parameter. Without arguments it -displays help for all configuration parameters. -', - ), - 'config-create' => array( - 'summary' => 'Create a Default configuration file', - 'function' => 'doConfigCreate', - 'shortcut' => 'coc', - 'options' => array( - 'windows' => array( - 'shortopt' => 'w', - 'doc' => 'create a config file for a windows install', - ), - ), - 'doc' => ' -Create a default configuration file with all directory configuration -variables set to subdirectories of , and save it as . -This is useful especially for creating a configuration file for a remote -PEAR installation (using the --remoteconfig option of install, upgrade, -and uninstall). -', - ), - ); - - /** - * PEAR_Command_Config constructor. - * - * @access public - */ - function PEAR_Command_Config(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function doConfigShow($command, $options, $params) - { - $layer = null; - if (is_array($params)) { - $layer = isset($params[0]) ? $params[0] : null; - } - - // $params[0] -> the layer - if ($error = $this->_checkLayer($layer)) { - return $this->raiseError("config-show:$error"); - } - - $keys = $this->config->getKeys(); - sort($keys); - $channel = isset($options['channel']) ? $options['channel'] : - $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - $channel = $reg->channelName($channel); - $data = array('caption' => 'Configuration (channel ' . $channel . '):'); - foreach ($keys as $key) { - $type = $this->config->getType($key); - $value = $this->config->get($key, $layer, $channel); - if ($type == 'password' && $value) { - $value = '********'; - } - - if ($value === false) { - $value = 'false'; - } elseif ($value === true) { - $value = 'true'; - } - - $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value); - } - - foreach ($this->config->getLayers() as $layer) { - $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer)); - } - - $this->ui->outputData($data, $command); - return true; - } - - function doConfigGet($command, $options, $params) - { - $args_cnt = is_array($params) ? count($params) : 0; - switch ($args_cnt) { - case 1: - $config_key = $params[0]; - $layer = null; - break; - case 2: - $config_key = $params[0]; - $layer = $params[1]; - if ($error = $this->_checkLayer($layer)) { - return $this->raiseError("config-get:$error"); - } - break; - case 0: - default: - return $this->raiseError("config-get expects 1 or 2 parameters"); - } - - $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command); - return true; - } - - function doConfigSet($command, $options, $params) - { - // $param[0] -> a parameter to set - // $param[1] -> the value for the parameter - // $param[2] -> the layer - $failmsg = ''; - if (count($params) < 2 || count($params) > 3) { - $failmsg .= "config-set expects 2 or 3 parameters"; - return PEAR::raiseError($failmsg); - } - - if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) { - $failmsg .= $error; - return PEAR::raiseError("config-set:$failmsg"); - } - - $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - $channel = $reg->channelName($channel); - if ($params[0] == 'default_channel' && !$reg->channelExists($params[1])) { - return $this->raiseError('Channel "' . $params[1] . '" does not exist'); - } - - if ($params[0] == 'preferred_mirror' - && ( - !$reg->mirrorExists($channel, $params[1]) && - (!$reg->channelExists($params[1]) || $channel != $params[1]) - ) - ) { - $msg = 'Channel Mirror "' . $params[1] . '" does not exist'; - $msg .= ' in your registry for channel "' . $channel . '".'; - $msg .= "\n" . 'Attempt to run "pear channel-update ' . $channel .'"'; - $msg .= ' if you believe this mirror should exist as you may'; - $msg .= ' have outdated channel information.'; - return $this->raiseError($msg); - } - - if (count($params) == 2) { - array_push($params, 'user'); - $layer = 'user'; - } else { - $layer = $params[2]; - } - - array_push($params, $channel); - if (!call_user_func_array(array(&$this->config, 'set'), $params)) { - array_pop($params); - $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel"; - } else { - $this->config->store($layer); - } - - if ($failmsg) { - return $this->raiseError($failmsg); - } - - $this->ui->outputData('config-set succeeded', $command); - return true; - } - - function doConfigHelp($command, $options, $params) - { - if (empty($params)) { - $params = $this->config->getKeys(); - } - - $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : ''); - $data['headline'] = array('Name', 'Type', 'Description'); - $data['border'] = true; - foreach ($params as $name) { - $type = $this->config->getType($name); - $docs = $this->config->getDocs($name); - if ($type == 'set') { - $docs = rtrim($docs) . "\nValid set: " . - implode(' ', $this->config->getSetValues($name)); - } - - $data['data'][] = array($name, $type, $docs); - } - - $this->ui->outputData($data, $command); - } - - function doConfigCreate($command, $options, $params) - { - if (count($params) != 2) { - return PEAR::raiseError('config-create: must have 2 parameters, root path and ' . - 'filename to save as'); - } - - $root = $params[0]; - // Clean up the DIRECTORY_SEPARATOR mess - $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; - $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"), - array('/', '/', '/'), - $root); - if ($root{0} != '/') { - if (!isset($options['windows'])) { - return PEAR::raiseError('Root directory must be an absolute path beginning ' . - 'with "/", was: "' . $root . '"'); - } - - if (!preg_match('/^[A-Za-z]:/', $root)) { - return PEAR::raiseError('Root directory must be an absolute path beginning ' . - 'with "\\" or "C:\\", was: "' . $root . '"'); - } - } - - $windows = isset($options['windows']); - if ($windows) { - $root = str_replace('/', '\\', $root); - } - - if (!file_exists($params[1]) && !@touch($params[1])) { - return PEAR::raiseError('Could not create "' . $params[1] . '"'); - } - - $params[1] = realpath($params[1]); - $config = &new PEAR_Config($params[1], '#no#system#config#', false, false); - if ($root{strlen($root) - 1} == '/') { - $root = substr($root, 0, strlen($root) - 1); - } - - $config->noRegistry(); - $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user'); - $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data"); - $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www"); - $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg"); - $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext"); - $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs"); - $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests"); - $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache"); - $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download"); - $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp"); - $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear"); - $config->writeConfigFile(); - $this->_showConfig($config); - $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"', - $command); - } - - function _showConfig(&$config) - { - $params = array('user'); - $keys = $config->getKeys(); - sort($keys); - $channel = 'pear.php.net'; - $data = array('caption' => 'Configuration (channel ' . $channel . '):'); - foreach ($keys as $key) { - $type = $config->getType($key); - $value = $config->get($key, 'user', $channel); - if ($type == 'password' && $value) { - $value = '********'; - } - - if ($value === false) { - $value = 'false'; - } elseif ($value === true) { - $value = 'true'; - } - $data['data'][$config->getGroup($key)][] = - array($config->getPrompt($key) , $key, $value); - } - - foreach ($config->getLayers() as $layer) { - $data['data']['Config Files'][] = - array(ucfirst($layer) . ' Configuration File', 'Filename' , - $config->getConfFile($layer)); - } - - $this->ui->outputData($data, 'config-show'); - return true; - } - - /** - * Checks if a layer is defined or not - * - * @param string $layer The layer to search for - * @return mixed False on no error or the error message - */ - function _checkLayer($layer = null) - { - if (!empty($layer) && $layer != 'default') { - $layers = $this->config->getLayers(); - if (!in_array($layer, $layers)) { - return " only the layers: \"" . implode('" or "', $layers) . "\" are supported"; - } - } - - return false; - } -}PEAR-1.9.0/PEAR/Command/Install.xml100664 764 764 20576 100664 11575 - - Install Package - doInstall - i - - - f - will overwrite newer installed packages - - - l - do not check for recommended dependency version - - - n - ignore dependencies, install anyway - - - r - do not install files, only register the package as installed - - - s - soft install, fail silently, or upgrade if already installed - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM - DIR - - - P - root directory used when packaging files, like RPM packaging - DIR - - - - force install even if there were errors - - - a - install all required and optional dependencies - - - o - install all required dependencies - - - O - do not attempt to download any urls or contact channels - - - p - Only list the packages that would be downloaded - - - [channel/]<package> ... -Installs one or more PEAR packages. You can specify a package to -install in four ways: - -"Package-1.0.tgz" : installs from a local file - -"http://example.com/Package-1.0.tgz" : installs from -anywhere on the net. - -"package.xml" : installs the package described in -package.xml. Useful for testing, or for wrapping a PEAR package in -another package manager such as RPM. - -"Package[-version/state][.tar]" : queries your default channel's server -({config master_server}) and downloads the newest package with -the preferred quality/state ({config preferred_state}). - -To retrieve Package version 1.1, use "Package-1.1," to retrieve -Package state beta, use "Package-beta." To retrieve an uncompressed -file, append .tar (make sure there is no file by the same name first) - -To download a package from another channel, prefix with the channel name like -"channel/Package" - -More than one package may be specified at once. It is ok to mix these -four ways of specifying packages. - - - - Upgrade Package - doInstall - up - - - c - upgrade packages from a specific channel - CHAN - - - f - overwrite newer installed packages - - - l - do not check for recommended dependency version - - - n - ignore dependencies, upgrade anyway - - - r - do not install files, only register the package as upgraded - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT) - DIR - - - - force install even if there were errors - - - a - install all required and optional dependencies - - - o - install all required dependencies - - - O - do not attempt to download any urls or contact channels - - - p - Only list the packages that would be downloaded - - - <package> ... -Upgrades one or more PEAR packages. See documentation for the -"install" command for ways to specify a package. - -When upgrading, your package will be updated if the provided new -package has a higher version number (use the -f option if you need to -upgrade anyway). - -More than one package may be specified at once. - - - - Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters] - doUpgradeAll - ua - - - c - upgrade packages from a specific channel - CHAN - - - n - ignore dependencies, upgrade anyway - - - r - do not install files, only register the package as upgraded - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM - DIR - - - - force install even if there were errors - - - - do not check for recommended dependency version - - - -WARNING: This function is deprecated in favor of using the upgrade command with no params - -Upgrades all packages that have a newer release available. Upgrades are -done only if there is a release available of the state specified in -"preferred_state" (currently {config preferred_state}), or a state considered -more stable. - - - - Un-install Package - doUninstall - un - - - n - ignore dependencies, uninstall anyway - - - r - do not remove files, only register the packages as not installed - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT) - DIR - - - - force install even if there were errors - - - O - do not attempt to uninstall remotely - - - [channel/]<package> ... -Uninstalls one or more PEAR packages. More than one package may be -specified at once. Prefix with channel name to uninstall from a -channel not in your default channel ({config default_channel}) - - - - Unpacks a Pecl Package - doBundle - bun - - - d - Optional destination directory for unpacking (defaults to current path or "ext" if exists) - DIR - - - f - Force the unpacking even if there were errors in the package - - - <package> -Unpacks a Pecl Package into the selected location. It will download the -package if needed. - - - - Run Post-Install Scripts bundled with a package - doRunScripts - rs - - <package> -Run post-installation scripts in package <package>, if any exist. - - -PEAR-1.9.0/PEAR/Command/Install.php100664 764 764 143164 100664 11603 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Install.php 287477 2009-08-19 14:19:43Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for installation or deinstallation/upgrading of - * packages. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Install extends PEAR_Command_Common -{ - // {{{ properties - - var $commands = array( - 'install' => array( - 'summary' => 'Install Package', - 'function' => 'doInstall', - 'shortcut' => 'i', - 'options' => array( - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'will overwrite newer installed packages', - ), - 'loose' => array( - 'shortopt' => 'l', - 'doc' => 'do not check for recommended dependency version', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, install anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as installed', - ), - 'soft' => array( - 'shortopt' => 's', - 'doc' => 'soft install, fail silently, or upgrade if already installed', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', - ), - 'packagingroot' => array( - 'shortopt' => 'P', - 'arg' => 'DIR', - 'doc' => 'root directory used when packaging files, like RPM packaging', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'alldeps' => array( - 'shortopt' => 'a', - 'doc' => 'install all required and optional dependencies', - ), - 'onlyreqdeps' => array( - 'shortopt' => 'o', - 'doc' => 'install all required dependencies', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to download any urls or contact channels', - ), - 'pretend' => array( - 'shortopt' => 'p', - 'doc' => 'Only list the packages that would be downloaded', - ), - ), - 'doc' => '[channel/] ... -Installs one or more PEAR packages. You can specify a package to -install in four ways: - -"Package-1.0.tgz" : installs from a local file - -"http://example.com/Package-1.0.tgz" : installs from -anywhere on the net. - -"package.xml" : installs the package described in -package.xml. Useful for testing, or for wrapping a PEAR package in -another package manager such as RPM. - -"Package[-version/state][.tar]" : queries your default channel\'s server -({config master_server}) and downloads the newest package with -the preferred quality/state ({config preferred_state}). - -To retrieve Package version 1.1, use "Package-1.1," to retrieve -Package state beta, use "Package-beta." To retrieve an uncompressed -file, append .tar (make sure there is no file by the same name first) - -To download a package from another channel, prefix with the channel name like -"channel/Package" - -More than one package may be specified at once. It is ok to mix these -four ways of specifying packages. -'), - 'upgrade' => array( - 'summary' => 'Upgrade Package', - 'function' => 'doInstall', - 'shortcut' => 'up', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'upgrade packages from a specific channel', - 'arg' => 'CHAN', - ), - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'overwrite newer installed packages', - ), - 'loose' => array( - 'shortopt' => 'l', - 'doc' => 'do not check for recommended dependency version', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, upgrade anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as upgraded', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'alldeps' => array( - 'shortopt' => 'a', - 'doc' => 'install all required and optional dependencies', - ), - 'onlyreqdeps' => array( - 'shortopt' => 'o', - 'doc' => 'install all required dependencies', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to download any urls or contact channels', - ), - 'pretend' => array( - 'shortopt' => 'p', - 'doc' => 'Only list the packages that would be downloaded', - ), - ), - 'doc' => ' ... -Upgrades one or more PEAR packages. See documentation for the -"install" command for ways to specify a package. - -When upgrading, your package will be updated if the provided new -package has a higher version number (use the -f option if you need to -upgrade anyway). - -More than one package may be specified at once. -'), - 'upgrade-all' => array( - 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]', - 'function' => 'doUpgradeAll', - 'shortcut' => 'ua', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'upgrade packages from a specific channel', - 'arg' => 'CHAN', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, upgrade anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as upgraded', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'loose' => array( - 'doc' => 'do not check for recommended dependency version', - ), - ), - 'doc' => ' -WARNING: This function is deprecated in favor of using the upgrade command with no params - -Upgrades all packages that have a newer release available. Upgrades are -done only if there is a release available of the state specified in -"preferred_state" (currently {config preferred_state}), or a state considered -more stable. -'), - 'uninstall' => array( - 'summary' => 'Un-install Package', - 'function' => 'doUninstall', - 'shortcut' => 'un', - 'options' => array( - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, uninstall anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not remove files, only register the packages as not installed', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to uninstall remotely', - ), - ), - 'doc' => '[channel/] ... -Uninstalls one or more PEAR packages. More than one package may be -specified at once. Prefix with channel name to uninstall from a -channel not in your default channel ({config default_channel}) -'), - 'bundle' => array( - 'summary' => 'Unpacks a Pecl Package', - 'function' => 'doBundle', - 'shortcut' => 'bun', - 'options' => array( - 'destination' => array( - 'shortopt' => 'd', - 'arg' => 'DIR', - 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', - ), - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'Force the unpacking even if there were errors in the package', - ), - ), - 'doc' => ' -Unpacks a Pecl Package into the selected location. It will download the -package if needed. -'), - 'run-scripts' => array( - 'summary' => 'Run Post-Install Scripts bundled with a package', - 'function' => 'doRunScripts', - 'shortcut' => 'rs', - 'options' => array( - ), - 'doc' => ' -Run post-installation scripts in package , if any exist. -'), - ); - - // }}} - // {{{ constructor - - /** - * PEAR_Command_Install constructor. - * - * @access public - */ - function PEAR_Command_Install(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - // }}} - - /** - * For unit testing purposes - */ - function &getDownloader(&$ui, $options, &$config) - { - if (!class_exists('PEAR_Downloader')) { - require_once 'PEAR/Downloader.php'; - } - $a = &new PEAR_Downloader($ui, $options, $config); - return $a; - } - - /** - * For unit testing purposes - */ - function &getInstaller(&$ui) - { - if (!class_exists('PEAR_Installer')) { - require_once 'PEAR/Installer.php'; - } - $a = &new PEAR_Installer($ui); - return $a; - } - - function enableExtension($binaries, $type) - { - if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { - return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); - } - $ini = $this->_parseIni($phpini); - if (PEAR::isError($ini)) { - return $ini; - } - $line = 0; - if ($type == 'extsrc' || $type == 'extbin') { - $search = 'extensions'; - $enable = 'extension'; - } else { - $search = 'zend_extensions'; - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $enable = 'zend_extension' . $debug . $ts; - } - foreach ($ini[$search] as $line => $extension) { - if (in_array($extension, $binaries, true) || in_array( - $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { - // already enabled - assume if one is, all are - return true; - } - } - if ($line) { - $newini = array_slice($ini['all'], 0, $line); - } else { - $newini = array(); - } - foreach ($binaries as $binary) { - if ($ini['extension_dir']) { - $binary = basename($binary); - } - $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n"); - } - $newini = array_merge($newini, array_slice($ini['all'], $line)); - $fp = @fopen($phpini, 'wb'); - if (!$fp) { - return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); - } - foreach ($newini as $line) { - fwrite($fp, $line); - } - fclose($fp); - return true; - } - - function disableExtension($binaries, $type) - { - if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { - return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); - } - $ini = $this->_parseIni($phpini); - if (PEAR::isError($ini)) { - return $ini; - } - $line = 0; - if ($type == 'extsrc' || $type == 'extbin') { - $search = 'extensions'; - $enable = 'extension'; - } else { - $search = 'zend_extensions'; - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $enable = 'zend_extension' . $debug . $ts; - } - $found = false; - foreach ($ini[$search] as $line => $extension) { - if (in_array($extension, $binaries, true) || in_array( - $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { - $found = true; - break; - } - } - if (!$found) { - // not enabled - return true; - } - $fp = @fopen($phpini, 'wb'); - if (!$fp) { - return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); - } - if ($line) { - $newini = array_slice($ini['all'], 0, $line); - // delete the enable line - $newini = array_merge($newini, array_slice($ini['all'], $line + 1)); - } else { - $newini = array_slice($ini['all'], 1); - } - foreach ($newini as $line) { - fwrite($fp, $line); - } - fclose($fp); - return true; - } - - function _parseIni($filename) - { - if (!file_exists($filename)) { - return PEAR::raiseError('php.ini "' . $filename . '" does not exist'); - } - - if (filesize($filename) > 300000) { - return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting'); - } - - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; - $zend_extension_line = 'zend_extension' . $debug . $ts; - $all = @file($filename); - if (!$all) { - return PEAR::raiseError('php.ini "' . $filename .'" could not be read'); - } - $zend_extensions = $extensions = array(); - // assume this is right, but pull from the php.ini if it is found - $extension_dir = ini_get('extension_dir'); - foreach ($all as $linenum => $line) { - $line = trim($line); - if (!$line) { - continue; - } - if ($line[0] == ';') { - continue; - } - if (strtolower(substr($line, 0, 13)) == 'extension_dir') { - $line = trim(substr($line, 13)); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $extension_dir = str_replace('"', '', array_shift($x)); - continue; - } - } - if (strtolower(substr($line, 0, 9)) == 'extension') { - $line = trim(substr($line, 9)); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $extensions[$linenum] = str_replace('"', '', array_shift($x)); - continue; - } - } - if (strtolower(substr($line, 0, strlen($zend_extension_line))) == - $zend_extension_line) { - $line = trim(substr($line, strlen($zend_extension_line))); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $zend_extensions[$linenum] = str_replace('"', '', array_shift($x)); - continue; - } - } - } - return array( - 'extensions' => $extensions, - 'zend_extensions' => $zend_extensions, - 'extension_dir' => $extension_dir, - 'all' => $all, - ); - } - - // {{{ doInstall() - - function doInstall($command, $options, $params) - { - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - - if (isset($options['installroot']) && isset($options['packagingroot'])) { - return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); - } - - $reg = &$this->config->getRegistry(); - $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - if (empty($this->installer)) { - $this->installer = &$this->getInstaller($this->ui); - } - - if ($command == 'upgrade' || $command == 'upgrade-all') { - // If people run the upgrade command but pass nothing, emulate a upgrade-all - if ($command == 'upgrade' && empty($params)) { - return $this->doUpgradeAll($command, $options, $params); - } - $options['upgrade'] = true; - } else { - $packages = $params; - } - - $instreg = &$reg; // instreg used to check if package is installed - if (isset($options['packagingroot']) && !isset($options['upgrade'])) { - $packrootphp_dir = $this->installer->_prependPath( - $this->config->get('php_dir', null, 'pear.php.net'), - $options['packagingroot']); - $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! - - if ($this->config->get('verbose') > 2) { - $this->ui->outputData('using package root: ' . $options['packagingroot']); - } - } - - $abstractpackages = $otherpackages = array(); - // parse params - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - - foreach ($params as $param) { - if (strpos($param, 'http://') === 0) { - $otherpackages[] = $param; - continue; - } - - if (strpos($param, 'channel://') === false && @file_exists($param)) { - if (isset($options['force'])) { - $otherpackages[] = $param; - continue; - } - - $pkg = new PEAR_PackageFile($this->config); - $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); - if (PEAR::isError($pf)) { - $otherpackages[] = $param; - continue; - } - - $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel()); - $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()); - $version_compare = version_compare($pf->getVersion(), $pversion, '<='); - if ($exists && $version_compare) { - if ($this->config->get('verbose')) { - $this->ui->outputData('Ignoring installed package ' . - $reg->parsedPackageNameToString( - array('package' => $pf->getPackage(), - 'channel' => $pf->getChannel()), true)); - } - continue; - } - $otherpackages[] = $param; - continue; - } - - $e = $reg->parsePackageName($param, $channel); - if (PEAR::isError($e)) { - $otherpackages[] = $param; - } else { - $abstractpackages[] = $e; - } - } - PEAR::staticPopErrorHandling(); - - // if there are any local package .tgz or remote static url, we can't - // filter. The filter only works for abstract packages - if (count($abstractpackages) && !isset($options['force'])) { - // when not being forced, only do necessary upgrades/installs - if (isset($options['upgrade'])) { - $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command); - } else { - $count = count($abstractpackages); - foreach ($abstractpackages as $i => $package) { - if (isset($package['group'])) { - // do not filter out install groups - continue; - } - - if ($instreg->packageExists($package['package'], $package['channel'])) { - if ($count > 1) { - if ($this->config->get('verbose')) { - $this->ui->outputData('Ignoring installed package ' . - $reg->parsedPackageNameToString($package, true)); - } - unset($abstractpackages[$i]); - } elseif ($count === 1) { - // Lets try to upgrade it since it's already installed - $options['upgrade'] = true; - } - } - } - } - $abstractpackages = - array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); - } elseif (count($abstractpackages)) { - $abstractpackages = - array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); - } - - $packages = array_merge($abstractpackages, $otherpackages); - if (!count($packages)) { - $c = ''; - if (isset($options['channel'])){ - $c .= ' in channel "' . $options['channel'] . '"'; - } - $this->ui->outputData('Nothing to ' . $command . $c); - return true; - } - - $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); - $errors = $downloaded = $binaries = array(); - $downloaded = &$this->downloader->download($packages); - if (PEAR::isError($downloaded)) { - return $this->raiseError($downloaded); - } - - $errors = $this->downloader->getErrorMsgs(); - if (count($errors)) { - $err = array(); - $err['data'] = array(); - foreach ($errors as $error) { - if ($error !== null) { - $err['data'][] = array($error); - } - } - - if (!empty($err['data'])) { - $err['headline'] = 'Install Errors'; - $this->ui->outputData($err); - } - - if (!count($downloaded)) { - return $this->raiseError("$command failed"); - } - } - - $data = array( - 'headline' => 'Packages that would be Installed' - ); - - if (isset($options['pretend'])) { - foreach ($downloaded as $package) { - $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); - } - $this->ui->outputData($data, 'pretend'); - return true; - } - - $this->installer->setOptions($options); - $this->installer->sortPackagesForInstall($downloaded); - if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { - $this->raiseError($err->getMessage()); - return true; - } - - $binaries = $extrainfo = array(); - foreach ($downloaded as $param) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->install($param, $options); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - $oldinfo = $info; - $pkg = &$param->getPackageFile(); - if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { - if (!($info = $pkg->installBinary($this->installer))) { - $this->ui->outputData('ERROR: ' .$oldinfo->getMessage()); - continue; - } - - // we just installed a different package than requested, - // let's change the param and info so that the rest of this works - $param = $info[0]; - $info = $info[1]; - } - } - - if (!is_array($info)) { - return $this->raiseError("$command failed"); - } - - if ($param->getPackageType() == 'extsrc' || - $param->getPackageType() == 'extbin' || - $param->getPackageType() == 'zendextsrc' || - $param->getPackageType() == 'zendextbin') { - $pkg = &$param->getPackageFile(); - if ($instbin = $pkg->getInstalledBinary()) { - $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); - } else { - $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); - } - - foreach ($instpkg->getFilelist() as $name => $atts) { - $pinfo = pathinfo($atts['installed_as']); - if (!isset($pinfo['extension']) || - in_array($pinfo['extension'], array('c', 'h'))) { - continue; // make sure we don't match php_blah.h - } - - if ((strpos($pinfo['basename'], 'php_') === 0 && - $pinfo['extension'] == 'dll') || - // most unices - $pinfo['extension'] == 'so' || - // hp-ux - $pinfo['extension'] == 'sl') { - $binaries[] = array($atts['installed_as'], $pinfo); - break; - } - } - - if (count($binaries)) { - foreach ($binaries as $pinfo) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($ret)) { - $extrainfo[] = $ret->getMessage(); - if ($param->getPackageType() == 'extsrc' || - $param->getPackageType() == 'extbin') { - $exttype = 'extension'; - } else { - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $exttype = 'zend_extension' . $debug . $ts; - } - $extrainfo[] = 'You should add "' . $exttype . '=' . - $pinfo[1]['basename'] . '" to php.ini'; - } else { - $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . - ' enabled in php.ini'; - } - } - } - } - - if ($this->config->get('verbose') > 0) { - $chan = $param->getChannel(); - $label = $reg->parsedPackageNameToString( - array( - 'channel' => $chan, - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - )); - $out = array('data' => "$command ok: $label"); - if (isset($info['release_warnings'])) { - $out['release_warnings'] = $info['release_warnings']; - } - $this->ui->outputData($out, $command); - - if (!isset($options['register-only']) && !isset($options['offline'])) { - if ($this->config->isDefinedLayer('ftp')) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->ftpInstall($param); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - $this->ui->outputData($info->getMessage()); - $this->ui->outputData("remote install failed: $label"); - } else { - $this->ui->outputData("remote install ok: $label"); - } - } - } - } - - $deps = $param->getDeps(); - if ($deps) { - if (isset($deps['group'])) { - $groups = $deps['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } - - foreach ($groups as $group) { - if ($group['attribs']['name'] == 'default') { - // default group is always installed, unless the user - // explicitly chooses to install another group - continue; - } - $extrainfo[] = $param->getPackage() . ': Optional feature ' . - $group['attribs']['name'] . ' available (' . - $group['attribs']['hint'] . ')'; - } - - $extrainfo[] = $param->getPackage() . - ': To install optional features use "pear install ' . - $reg->parsedPackageNameToString( - array('package' => $param->getPackage(), - 'channel' => $param->getChannel()), true) . - '#featurename"'; - } - } - - $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel()); - // $pkg may be NULL if install is a 'fake' install via --packagingroot - if (is_object($pkg)) { - $pkg->setConfig($this->config); - if ($list = $pkg->listPostinstallScripts()) { - $pn = $reg->parsedPackageNameToString(array('channel' => - $param->getChannel(), 'package' => $param->getPackage()), true); - $extrainfo[] = $pn . ' has post-install scripts:'; - foreach ($list as $file) { - $extrainfo[] = $file; - } - $extrainfo[] = $param->getPackage() . - ': Use "pear run-scripts ' . $pn . '" to finish setup.'; - $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; - } - } - } - - if (count($extrainfo)) { - foreach ($extrainfo as $info) { - $this->ui->outputData($info); - } - } - - return true; - } - - // }}} - // {{{ doUpgradeAll() - - function doUpgradeAll($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - $upgrade = array(); - - if (isset($options['channel'])) { - $channels = array($options['channel']); - } else { - $channels = $reg->listChannels(); - } - - foreach ($channels as $channel) { - if ($channel == '__uri') { - continue; - } - - // parse name with channel - foreach ($reg->listPackages($channel) as $name) { - $upgrade[] = $reg->parsedPackageNameToString(array( - 'channel' => $channel, - 'package' => $name - )); - } - } - - $err = $this->doInstall($command, $options, $upgrade); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - } - } - - // }}} - // {{{ doUninstall() - - function doUninstall($command, $options, $params) - { - if (count($params) < 1) { - return $this->raiseError("Please supply the package(s) you want to uninstall"); - } - - if (empty($this->installer)) { - $this->installer = &$this->getInstaller($this->ui); - } - - if (isset($options['remoteconfig'])) { - $e = $this->config->readFTPConfigFile($options['remoteconfig']); - if (!PEAR::isError($e)) { - $this->installer->setConfig($this->config); - } - } - - $reg = &$this->config->getRegistry(); - $newparams = array(); - $binaries = array(); - $badparams = array(); - foreach ($params as $pkg) { - $channel = $this->config->get('default_channel'); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($pkg, $channel); - PEAR::staticPopErrorHandling(); - if (!$parsed || PEAR::isError($parsed)) { - $badparams[] = $pkg; - continue; - } - $package = $parsed['package']; - $channel = $parsed['channel']; - $info = &$reg->getPackage($package, $channel); - if ($info === null && - ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) { - // make sure this isn't a package that has flipped from pear to pecl but - // used a package.xml 1.0 - $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net'; - $info = &$reg->getPackage($package, $testc); - if ($info !== null) { - $channel = $testc; - } - } - if ($info === null) { - $badparams[] = $pkg; - } else { - $newparams[] = &$info; - // check for binary packages (this is an alias for those packages if so) - if ($installedbinary = $info->getInstalledBinary()) { - $this->ui->log('adding binary package ' . - $reg->parsedPackageNameToString(array('channel' => $channel, - 'package' => $installedbinary), true)); - $newparams[] = &$reg->getPackage($installedbinary, $channel); - } - // add the contents of a dependency group to the list of installed packages - if (isset($parsed['group'])) { - $group = $info->getDependencyGroup($parsed['group']); - if ($group) { - $installed = $reg->getInstalledGroup($group); - if ($installed) { - foreach ($installed as $i => $p) { - $newparams[] = &$installed[$i]; - } - } - } - } - } - } - $err = $this->installer->sortPackagesForUninstall($newparams); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - return true; - } - $params = $newparams; - // twist this to use it to check on whether dependent packages are also being uninstalled - // for circular dependencies like subpackages - $this->installer->setUninstallPackages($newparams); - $params = array_merge($params, $badparams); - $binaries = array(); - foreach ($params as $pkg) { - $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); - if ($err = $this->installer->uninstall($pkg, $options)) { - $this->installer->popErrorHandling(); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - continue; - } - if ($pkg->getPackageType() == 'extsrc' || - $pkg->getPackageType() == 'extbin' || - $pkg->getPackageType() == 'zendextsrc' || - $pkg->getPackageType() == 'zendextbin') { - if ($instbin = $pkg->getInstalledBinary()) { - continue; // this will be uninstalled later - } - - foreach ($pkg->getFilelist() as $name => $atts) { - $pinfo = pathinfo($atts['installed_as']); - if (!isset($pinfo['extension']) || - in_array($pinfo['extension'], array('c', 'h'))) { - continue; // make sure we don't match php_blah.h - } - if ((strpos($pinfo['basename'], 'php_') === 0 && - $pinfo['extension'] == 'dll') || - // most unices - $pinfo['extension'] == 'so' || - // hp-ux - $pinfo['extension'] == 'sl') { - $binaries[] = array($atts['installed_as'], $pinfo); - break; - } - } - if (count($binaries)) { - foreach ($binaries as $pinfo) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($ret)) { - $extrainfo[] = $ret->getMessage(); - if ($pkg->getPackageType() == 'extsrc' || - $pkg->getPackageType() == 'extbin') { - $exttype = 'extension'; - } else { - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $exttype = 'zend_extension' . $debug . $ts; - } - $this->ui->outputData('Unable to remove "' . $exttype . '=' . - $pinfo[1]['basename'] . '" from php.ini', $command); - } else { - $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() . - ' disabled in php.ini', $command); - } - } - } - } - $savepkg = $pkg; - if ($this->config->get('verbose') > 0) { - if (is_object($pkg)) { - $pkg = $reg->parsedPackageNameToString($pkg); - } - $this->ui->outputData("uninstall ok: $pkg", $command); - } - if (!isset($options['offline']) && is_object($savepkg) && - defined('PEAR_REMOTEINSTALL_OK')) { - if ($this->config->isDefinedLayer('ftp')) { - $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->ftpUninstall($savepkg); - $this->installer->popErrorHandling(); - if (PEAR::isError($info)) { - $this->ui->outputData($info->getMessage()); - $this->ui->outputData("remote uninstall failed: $pkg"); - } else { - $this->ui->outputData("remote uninstall ok: $pkg"); - } - } - } - } else { - $this->installer->popErrorHandling(); - if (!is_object($pkg)) { - return $this->raiseError("uninstall failed: $pkg"); - } - $pkg = $reg->parsedPackageNameToString($pkg); - } - } - - return true; - } - - // }}} - - - // }}} - // {{{ doBundle() - /* - (cox) It just downloads and untars the package, does not do - any check that the PEAR_Installer::_installFile() does. - */ - - function doBundle($command, $options, $params) - { - $opts = array( - 'force' => true, - 'nodeps' => true, - 'soft' => true, - 'downloadonly' => true - ); - $downloader = &$this->getDownloader($this->ui, $opts, $this->config); - $reg = &$this->config->getRegistry(); - if (count($params) < 1) { - return $this->raiseError("Please supply the package you want to bundle"); - } - - if (isset($options['destination'])) { - if (!is_dir($options['destination'])) { - System::mkdir('-p ' . $options['destination']); - } - $dest = realpath($options['destination']); - } else { - $pwd = getcwd(); - $dir = $pwd . DIRECTORY_SEPARATOR . 'ext'; - $dest = is_dir($dir) ? $dir : $pwd; - } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $downloader->setDownloadDir($dest); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($err)) { - return PEAR::raiseError('download directory "' . $dest . - '" is not writeable.'); - } - $result = &$downloader->download(array($params[0])); - if (PEAR::isError($result)) { - return $result; - } - if (!isset($result[0])) { - return $this->raiseError('unable to unpack ' . $params[0]); - } - $pkgfile = &$result[0]->getPackageFile(); - $pkgname = $pkgfile->getName(); - $pkgversion = $pkgfile->getVersion(); - - // Unpacking ------------------------------------------------- - $dest .= DIRECTORY_SEPARATOR . $pkgname; - $orig = $pkgname . '-' . $pkgversion; - - $tar = &new Archive_Tar($pkgfile->getArchiveFile()); - if (!$tar->extractModify($dest, $orig)) { - return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile()); - } - $this->ui->outputData("Package ready at '$dest'"); - // }}} - } - - // }}} - - function doRunScripts($command, $options, $params) - { - if (!isset($params[0])) { - return $this->raiseError('run-scripts expects 1 parameter: a package name'); - } - - $reg = &$this->config->getRegistry(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($parsed)) { - return $this->raiseError($parsed); - } - - $package = &$reg->getPackage($parsed['package'], $parsed['channel']); - if (!is_object($package)) { - return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry'); - } - - $package->setConfig($this->config); - $package->runPostinstallScripts(); - $this->ui->outputData('Install scripts complete', $command); - return true; - } - - /** - * Given a list of packages, filter out those ones that are already up to date - * - * @param $packages: packages, in parsed array format ! - * @return list of packages that can be upgraded - */ - function _filterUptodatePackages($packages, $command) - { - $reg = &$this->config->getRegistry(); - $latestReleases = array(); - - $ret = array(); - foreach ($packages as $package) { - if (isset($package['group'])) { - $ret[] = $package; - continue; - } - - $channel = $package['channel']; - $name = $package['package']; - if (!$reg->packageExists($name, $channel)) { - $ret[] = $package; - continue; - } - - if (!isset($latestReleases[$channel])) { - // fill in cache for this channel - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); - } - - $base2 = false; - $preferred_mirror = $this->config->get('preferred_mirror', null, $channel); - if ($chan->supportsREST($preferred_mirror) && - ( - //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || - ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - ) { - $dorest = true; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!isset($package['state'])) { - $state = $this->config->get('preferred_state', null, $channel); - } else { - $state = $package['state']; - } - - if ($dorest) { - if ($base2) { - $rest = &$this->config->getREST('1.4', array()); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', array()); - } - - $installed = array_flip($reg->listPackages($channel)); - $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); - } - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($latest)) { - $this->ui->outputData('Error getting channel info from ' . $channel . - ': ' . $latest->getMessage()); - continue; - } - - $latestReleases[$channel] = array_change_key_case($latest); - } - - // check package for latest release - $name_lower = strtolower($name); - if (isset($latestReleases[$channel][$name_lower])) { - // if not set, up to date - $inst_version = $reg->packageInfo($name, 'version', $channel); - $channel_version = $latestReleases[$channel][$name_lower]['version']; - if (version_compare($channel_version, $inst_version, 'le')) { - // installed version is up-to-date - continue; - } - - // maintain BC - if ($command == 'upgrade-all') { - $this->ui->outputData(array('data' => 'Will upgrade ' . - $reg->parsedPackageNameToString($package)), $command); - } - $ret[] = $package; - } - } - - return $ret; - } -}PEAR-1.9.0/PEAR/Command/Mirror.xml100664 764 764 1151 100664 11405 - - Downloads each available package from the default channel - doDownloadAll - da - - - c - specify a channel other than the default channel - CHAN - - - -Requests a list of available packages from the default channel ({config default_channel}) -and downloads them to current working directory. Note: only -packages within preferred_state ({config preferred_state}) will be downloaded - -PEAR-1.9.0/PEAR/Command/Mirror.php100664 764 764 10762 100664 11424 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Mirror.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.2.0 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for providing file mirrors - * - * @category pear - * @package PEAR - * @author Alexander Merz - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.2.0 - */ -class PEAR_Command_Mirror extends PEAR_Command_Common -{ - var $commands = array( - 'download-all' => array( - 'summary' => 'Downloads each available package from the default channel', - 'function' => 'doDownloadAll', - 'shortcut' => 'da', - 'options' => array( - 'channel' => - array( - 'shortopt' => 'c', - 'doc' => 'specify a channel other than the default channel', - 'arg' => 'CHAN', - ), - ), - 'doc' => ' -Requests a list of available packages from the default channel ({config default_channel}) -and downloads them to current working directory. Note: only -packages within preferred_state ({config preferred_state}) will be downloaded' - ), - ); - - /** - * PEAR_Command_Mirror constructor. - * - * @access public - * @param object PEAR_Frontend a reference to an frontend - * @param object PEAR_Config a reference to the configuration data - */ - function PEAR_Command_Mirror(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - /** - * For unit-testing - */ - function &factory($a) - { - $a = &PEAR_Command::factory($a, $this->config); - return $a; - } - - /** - * retrieves a list of avaible Packages from master server - * and downloads them - * - * @access public - * @param string $command the command - * @param array $options the command options before the command - * @param array $params the stuff after the command name - * @return bool true if succesful - * @throw PEAR_Error - */ - function doDownloadAll($command, $options, $params) - { - $savechannel = $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - $channel = isset($options['channel']) ? $options['channel'] : - $this->config->get('default_channel'); - if (!$reg->channelExists($channel)) { - $this->config->set('default_channel', $savechannel); - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - $this->config->set('default_channel', $channel); - - $this->ui->outputData('Using Channel ' . $this->config->get('default_channel')); - $chan = $reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); - } - - if ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { - $rest = &$this->config->getREST('1.0', array()); - $remoteInfo = array_flip($rest->listPackages($base, $channel)); - } - - if (PEAR::isError($remoteInfo)) { - return $remoteInfo; - } - - $cmd = &$this->factory("download"); - if (PEAR::isError($cmd)) { - return $cmd; - } - - $this->ui->outputData('Using Preferred State of ' . - $this->config->get('preferred_state')); - $this->ui->outputData('Gathering release information, please wait...'); - - /** - * Error handling not necessary, because already done by - * the download command - */ - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo)); - PEAR::staticPopErrorHandling(); - $this->config->set('default_channel', $savechannel); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage()); - } - - return true; - } -}PEAR-1.9.0/PEAR/Command/Package.xml100664 764 764 16066 100664 11521 - - Build Package - doPackage - p - - - Z - Do not gzip the package file - - - n - Print the name of the packaged file. - - - [descfile] [descfile2] -Creates a PEAR package from its description file (usually called -package.xml). If a second packagefile is passed in, then -the packager will check to make sure that one is a package.xml -version 1.0, and the other is a package.xml version 2.0. The -package.xml version 1.0 will be saved as "package.xml" in the archive, -and the other as "package2.xml" in the archive" - - - - Validate Package Consistency - doPackageValidate - pv - - - - - - Run a "cvs diff" for all files in a package - doCvsDiff - cd - - - q - Be quiet - - - Q - Be really quiet - - - D - Diff against revision of DATE - DATE - - - R - Diff against tag for package release REL - REL - - - r - Diff against revision REV - REV - - - c - Generate context diff - - - u - Generate unified diff - - - i - Ignore case, consider upper- and lower-case letters equivalent - - - b - Ignore changes in amount of white space - - - B - Ignore changes that insert or delete blank lines - - - - Report only whether the files differ, no details - - - n - Don't do anything, just pretend - - - <package.xml> -Compares all the files in a package. Without any options, this -command will compare the current code with the last checked-in code. -Using the -r or -R option you may compare the current code with that -of a specific release. - - - - Set SVN Release Tag - doSvnTag - sv - - - q - Be quiet - - - F - Move (slide) tag if it exists - - - d - Remove tag - - - n - Don't do anything, just pretend - - - <package.xml> [files...] - Sets a SVN tag on all files in a package. Use this command after you have - packaged a distribution tarball with the "package" command to tag what - revisions of what files were in that release. If need to fix something - after running cvstag once, but before the tarball is released to the public, - use the "slide" option to move the release tag. - - to include files (such as a second package.xml, or tests not included in the - release), pass them as additional parameters. - - - - Set CVS Release Tag - doCvsTag - ct - - - q - Be quiet - - - Q - Be really quiet - - - F - Move (slide) tag if it exists - - - d - Remove tag - - - n - Don't do anything, just pretend - - - <package.xml> [files...] -Sets a CVS tag on all files in a package. Use this command after you have -packaged a distribution tarball with the "package" command to tag what -revisions of what files were in that release. If need to fix something -after running cvstag once, but before the tarball is released to the public, -use the "slide" option to move the release tag. - -to include files (such as a second package.xml, or tests not included in the -release), pass them as additional parameters. - - - - Show package dependencies - doPackageDependencies - pd - - <package-file> or <package.xml> or <install-package-name> -List all dependencies the package has. -Can take a tgz / tar file, package.xml or a package name of an installed package. - - - Sign a package distribution file - doSign - si - - - v - Display GnuPG output - - - <package-file> -Signs a package distribution (.tar or .tgz) file with GnuPG. - - - Builds an RPM spec file from a PEAR package - doMakeRPM - rpm - - - t - Use FILE as RPM spec file template - FILE - - - p - Use FORMAT as format string for RPM package name, %s is replaced -by the PEAR package name, defaults to "PEAR::%s". - FORMAT - - - <package-file> - -Creates an RPM .spec file for wrapping a PEAR package inside an RPM -package. Intended to be used from the SPECS directory, with the PEAR -package tarball in the SOURCES directory: - -$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz -Wrote RPM spec file PEAR::Net_Geo-1.0.spec -$ rpm -bb PEAR::Net_Socket-1.0.spec -... -Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm - - - - Convert a package.xml 1.0 to package.xml 2.0 format - doConvert - c2 - - - f - do not beautify the filelist. - - - [descfile] [descfile2] -Converts a package.xml in 1.0 format into a package.xml -in 2.0 format. The new file will be named package2.xml by default, -and package.xml will be used as the old file by default. -This is not the most intelligent conversion, and should only be -used for automated conversion or learning the format. - - -PEAR-1.9.0/PEAR/Command/Package.php100664 764 764 114657 100664 11535 - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Package.php 287559 2009-08-21 22:33:10Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for login/logout - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ - -class PEAR_Command_Package extends PEAR_Command_Common -{ - var $commands = array( - 'package' => array( - 'summary' => 'Build Package', - 'function' => 'doPackage', - 'shortcut' => 'p', - 'options' => array( - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'Do not gzip the package file' - ), - 'showname' => array( - 'shortopt' => 'n', - 'doc' => 'Print the name of the packaged file.', - ), - ), - 'doc' => '[descfile] [descfile2] -Creates a PEAR package from its description file (usually called -package.xml). If a second packagefile is passed in, then -the packager will check to make sure that one is a package.xml -version 1.0, and the other is a package.xml version 2.0. The -package.xml version 1.0 will be saved as "package.xml" in the archive, -and the other as "package2.xml" in the archive" -' - ), - 'package-validate' => array( - 'summary' => 'Validate Package Consistency', - 'function' => 'doPackageValidate', - 'shortcut' => 'pv', - 'options' => array(), - 'doc' => ' -', - ), - 'cvsdiff' => array( - 'summary' => 'Run a "cvs diff" for all files in a package', - 'function' => 'doCvsDiff', - 'shortcut' => 'cd', - 'options' => array( - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Be quiet', - ), - 'reallyquiet' => array( - 'shortopt' => 'Q', - 'doc' => 'Be really quiet', - ), - 'date' => array( - 'shortopt' => 'D', - 'doc' => 'Diff against revision of DATE', - 'arg' => 'DATE', - ), - 'release' => array( - 'shortopt' => 'R', - 'doc' => 'Diff against tag for package release REL', - 'arg' => 'REL', - ), - 'revision' => array( - 'shortopt' => 'r', - 'doc' => 'Diff against revision REV', - 'arg' => 'REV', - ), - 'context' => array( - 'shortopt' => 'c', - 'doc' => 'Generate context diff', - ), - 'unified' => array( - 'shortopt' => 'u', - 'doc' => 'Generate unified diff', - ), - 'ignore-case' => array( - 'shortopt' => 'i', - 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent', - ), - 'ignore-whitespace' => array( - 'shortopt' => 'b', - 'doc' => 'Ignore changes in amount of white space', - ), - 'ignore-blank-lines' => array( - 'shortopt' => 'B', - 'doc' => 'Ignore changes that insert or delete blank lines', - ), - 'brief' => array( - 'doc' => 'Report only whether the files differ, no details', - ), - 'dry-run' => array( - 'shortopt' => 'n', - 'doc' => 'Don\'t do anything, just pretend', - ), - ), - 'doc' => ' -Compares all the files in a package. Without any options, this -command will compare the current code with the last checked-in code. -Using the -r or -R option you may compare the current code with that -of a specific release. -', - ), - 'svntag' => array( - 'summary' => 'Set SVN Release Tag', - 'function' => 'doSvnTag', - 'shortcut' => 'sv', - 'options' => array( - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Be quiet', - ), - 'slide' => array( - 'shortopt' => 'F', - 'doc' => 'Move (slide) tag if it exists', - ), - 'delete' => array( - 'shortopt' => 'd', - 'doc' => 'Remove tag', - ), - 'dry-run' => array( - 'shortopt' => 'n', - 'doc' => 'Don\'t do anything, just pretend', - ), - ), - 'doc' => ' [files...] - Sets a SVN tag on all files in a package. Use this command after you have - packaged a distribution tarball with the "package" command to tag what - revisions of what files were in that release. If need to fix something - after running cvstag once, but before the tarball is released to the public, - use the "slide" option to move the release tag. - - to include files (such as a second package.xml, or tests not included in the - release), pass them as additional parameters. - ', - ), - 'cvstag' => array( - 'summary' => 'Set CVS Release Tag', - 'function' => 'doCvsTag', - 'shortcut' => 'ct', - 'options' => array( - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Be quiet', - ), - 'reallyquiet' => array( - 'shortopt' => 'Q', - 'doc' => 'Be really quiet', - ), - 'slide' => array( - 'shortopt' => 'F', - 'doc' => 'Move (slide) tag if it exists', - ), - 'delete' => array( - 'shortopt' => 'd', - 'doc' => 'Remove tag', - ), - 'dry-run' => array( - 'shortopt' => 'n', - 'doc' => 'Don\'t do anything, just pretend', - ), - ), - 'doc' => ' [files...] -Sets a CVS tag on all files in a package. Use this command after you have -packaged a distribution tarball with the "package" command to tag what -revisions of what files were in that release. If need to fix something -after running cvstag once, but before the tarball is released to the public, -use the "slide" option to move the release tag. - -to include files (such as a second package.xml, or tests not included in the -release), pass them as additional parameters. -', - ), - 'package-dependencies' => array( - 'summary' => 'Show package dependencies', - 'function' => 'doPackageDependencies', - 'shortcut' => 'pd', - 'options' => array(), - 'doc' => ' or or -List all dependencies the package has. -Can take a tgz / tar file, package.xml or a package name of an installed package.' - ), - 'sign' => array( - 'summary' => 'Sign a package distribution file', - 'function' => 'doSign', - 'shortcut' => 'si', - 'options' => array( - 'verbose' => array( - 'shortopt' => 'v', - 'doc' => 'Display GnuPG output', - ), - ), - 'doc' => ' -Signs a package distribution (.tar or .tgz) file with GnuPG.', - ), - 'makerpm' => array( - 'summary' => 'Builds an RPM spec file from a PEAR package', - 'function' => 'doMakeRPM', - 'shortcut' => 'rpm', - 'options' => array( - 'spec-template' => array( - 'shortopt' => 't', - 'arg' => 'FILE', - 'doc' => 'Use FILE as RPM spec file template' - ), - 'rpm-pkgname' => array( - 'shortopt' => 'p', - 'arg' => 'FORMAT', - 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced -by the PEAR package name, defaults to "PEAR::%s".', - ), - ), - 'doc' => ' - -Creates an RPM .spec file for wrapping a PEAR package inside an RPM -package. Intended to be used from the SPECS directory, with the PEAR -package tarball in the SOURCES directory: - -$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz -Wrote RPM spec file PEAR::Net_Geo-1.0.spec -$ rpm -bb PEAR::Net_Socket-1.0.spec -... -Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm -', - ), - 'convert' => array( - 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format', - 'function' => 'doConvert', - 'shortcut' => 'c2', - 'options' => array( - 'flat' => array( - 'shortopt' => 'f', - 'doc' => 'do not beautify the filelist.', - ), - ), - 'doc' => '[descfile] [descfile2] -Converts a package.xml in 1.0 format into a package.xml -in 2.0 format. The new file will be named package2.xml by default, -and package.xml will be used as the old file by default. -This is not the most intelligent conversion, and should only be -used for automated conversion or learning the format. -' - ), - ); - - var $output; - - /** - * PEAR_Command_Package constructor. - * - * @access public - */ - function PEAR_Command_Package(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function _displayValidationResults($err, $warn, $strict = false) - { - foreach ($err as $e) { - $this->output .= "Error: $e\n"; - } - foreach ($warn as $w) { - $this->output .= "Warning: $w\n"; - } - $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n", - sizeof($err), sizeof($warn)); - if ($strict && count($err) > 0) { - $this->output .= "Fix these errors and try again."; - return false; - } - return true; - } - - function &getPackager() - { - if (!class_exists('PEAR_Packager')) { - require_once 'PEAR/Packager.php'; - } - $a = &new PEAR_Packager; - return $a; - } - - function &getPackageFile($config, $debug = false, $tmpdir = null) - { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - $a = &new PEAR_PackageFile($config, $debug, $tmpdir); - $common = new PEAR_Common; - $common->ui = $this->ui; - $a->setLogger($common); - return $a; - } - - function doPackage($command, $options, $params) - { - $this->output = ''; - $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; - $pkg2 = isset($params[1]) ? $params[1] : null; - if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) { - $pkg2 = 'package2.xml'; - } - - $packager = &$this->getPackager(); - $compress = empty($options['nocompress']) ? true : false; - $result = $packager->package($pkginfofile, $compress, $pkg2); - if (PEAR::isError($result)) { - return $this->raiseError($result); - } - - // Don't want output, only the package file name just created - if (isset($options['showname'])) { - $this->output = $result; - } - - if ($this->output) { - $this->ui->outputData($this->output, $command); - } - - return true; - } - - function doPackageValidate($command, $options, $params) - { - $this->output = ''; - if (count($params) < 1) { - $params[0] = 'package.xml'; - } - - $obj = &$this->getPackageFile($this->config, $this->_debug); - $obj->rawReturn(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL); - } else { - $archive = $info->getArchiveFile(); - $tar = &new Archive_Tar($archive); - $tar->extract(dirname($info->getPackageFile())); - $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR . - $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR . - basename($info->getPackageFile())); - } - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $valid = false; - if ($info->getPackagexmlVersion() == '2.0') { - if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) { - $info->flattenFileList(); - $valid = $info->validate(PEAR_VALIDATE_PACKAGING); - } - } else { - $valid = $info->validate(PEAR_VALIDATE_PACKAGING); - } - - $err = $warn = array(); - if ($errors = $info->getValidationWarnings()) { - foreach ($errors as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - $this->_displayValidationResults($err, $warn); - $this->ui->outputData($this->output, $command); - return true; - } - - function doSvnTag($command, $options, $params) - { - $this->output = ''; - $_cmd = $command; - if (count($params) < 1) { - $help = $this->getHelp($command); - return $this->raiseError("$command: missing parameter: $help[0]"); - } - - $packageFile = realpath($params[0]); - $dir = dirname($packageFile); - $dir = substr($dir, strrpos($dir, '/') + 1); - $obj = &$this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $err = $warn = array(); - if (!$info->validate()) { - foreach ($info->getValidationWarnings() as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - if (!$this->_displayValidationResults($err, $warn, true)) { - $this->ui->outputData($this->output, $command); - return $this->raiseError('SVN tag failed'); - } - - $version = $info->getVersion(); - $package = $info->getName(); - $svntag = "$package-$version"; - - if (isset($options['delete'])) { - return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options); - } - - $path = $this->_svnFindPath($packageFile); - - // Check if there are any modified files - $fp = popen('svn st --xml ' . dirname($packageFile), "r"); - $out = ''; - while ($line = fgets($fp, 1024)) { - $out .= rtrim($line)."\n"; - } - pclose($fp); - - if (!isset($options['quiet']) && strpos($out, 'item="modified"')) { - $params = array(array( - 'name' => 'modified', - 'type' => 'yesno', - 'default' => 'no', - 'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not commited, do you still want to tag ' . $version . '?', - )); - $answers = $this->ui->confirmDialog($params); - - if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) { - return true; - } - } - - if (isset($options['slide'])) { - $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options); - } - - // Check if tag already exists - $releaseTag = $path['local']['base'] . 'tags/' . $svntag; - $existsCommand = 'svn ls ' . $path['base'] . 'tags/'; - - $fp = popen($existsCommand, "r"); - $out = ''; - while ($line = fgets($fp, 1024)) { - $out .= rtrim($line)."\n"; - } - pclose($fp); - - if (in_array($svntag . '/', explode("\n", $out))) { - $this->ui->outputData($this->output, $command); - return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.'); - } else { - $makeCommand = 'svn mkdir ' . $releaseTag; - $this->output .= "+ $makeCommand\n"; - if (empty($options['dry-run'])) { - // We need to create the tag dir. - $fp = popen($makeCommand, "r"); - $out = ''; - while ($line = fgets($fp, 1024)) { - $out .= rtrim($line)."\n"; - } - pclose($fp); - $this->output .= "$out\n"; - } - } - - $command = 'svn'; - if (isset($options['quiet'])) { - $command .= ' -q'; - } - - $command .= ' copy --parents '; - - $dir = dirname($packageFile); - $dir = substr($dir, strrpos($dir, '/') + 1); - $files = array_keys($info->getFilelist()); - $commands = array(); - foreach ($files as $file) { - if (!file_exists($file)) { - $file = $dir . DIRECTORY_SEPARATOR . $file; - } - $commands[] = $command . ' ' . escapeshellarg($file) . ' ' . - escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file); - } - - $this->output .= implode("\n", $commands) . "\n"; - if (empty($options['dry-run'])) { - foreach ($commands as $command) { - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - } - - $command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n"; - $this->output .= "+ $command\n"; - if (empty($options['dry-run'])) { - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - - $this->ui->outputData($this->output, $_cmd); - return true; - } - - function _svnFindPath($file) - { - $xml = ''; - $command = "svn info --xml $file"; - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $xml .= rtrim($line)."\n"; - } - pclose($fp); - $url_tag = strpos($xml, ''); - $url = substr($xml, $url_tag + 5, strpos($xml, '', $url_tag + 5) - ($url_tag + 5)); - - $path = array(); - $path['from'] = substr($url, 0, strrpos($url, '/')); - $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1); - - // Figure out the local paths - $pos = strpos($file, '/trunk/'); - if ($pos === false) { - $pos = strpos($file, '/branches/'); - } - $path['local']['base'] = substr($file, 0, $pos + 1); - - return $path; - } - - function _svnRemoveTag($version, $package, $tag, $packageFile, $options) - { - $command = 'svn'; - - if (isset($options['quiet'])) { - $command .= ' -q'; - } - - $command .= ' remove'; - $command .= ' -m "Removing tag for the ' . $version . ' release."'; - - $path = $this->_svnFindPath($packageFile); - $command .= ' ' . $path['base'] . 'tags/' . $tag; - - - if ($this->config->get('verbose') > 1) { - $this->output .= "+ $command\n"; - } - - $this->output .= "+ $command\n"; - if (empty($options['dry-run'])) { - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - - $this->ui->outputData($this->output, $command); - return true; - } - - function doCvsTag($command, $options, $params) - { - $this->output = ''; - $_cmd = $command; - if (count($params) < 1) { - $help = $this->getHelp($command); - return $this->raiseError("$command: missing parameter: $help[0]"); - } - - $packageFile = realpath($params[0]); - $obj = &$this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $err = $warn = array(); - if (!$info->validate()) { - foreach ($info->getValidationWarnings() as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - if (!$this->_displayValidationResults($err, $warn, true)) { - $this->ui->outputData($this->output, $command); - return $this->raiseError('CVS tag failed'); - } - - $version = $info->getVersion(); - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); - $cvstag = "RELEASE_$cvsversion"; - $files = array_keys($info->getFilelist()); - $command = 'cvs'; - if (isset($options['quiet'])) { - $command .= ' -q'; - } - - if (isset($options['reallyquiet'])) { - $command .= ' -Q'; - } - - $command .= ' tag'; - if (isset($options['slide'])) { - $command .= ' -F'; - } - - if (isset($options['delete'])) { - $command .= ' -d'; - } - - $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); - array_shift($params); - if (count($params)) { - // add in additional files to be tagged - $files = array_merge($files, $params); - } - - $dir = dirname($packageFile); - $dir = substr($dir, strrpos($dir, '/') + 1); - foreach ($files as $file) { - if (!file_exists($file)) { - $file = $dir . DIRECTORY_SEPARATOR . $file; - } - $command .= ' ' . escapeshellarg($file); - } - - if ($this->config->get('verbose') > 1) { - $this->output .= "+ $command\n"; - } - - $this->output .= "+ $command\n"; - if (empty($options['dry-run'])) { - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - - $this->ui->outputData($this->output, $_cmd); - return true; - } - - function doCvsDiff($command, $options, $params) - { - $this->output = ''; - if (sizeof($params) < 1) { - $help = $this->getHelp($command); - return $this->raiseError("$command: missing parameter: $help[0]"); - } - - $file = realpath($params[0]); - $obj = &$this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $err = $warn = array(); - if (!$info->validate()) { - foreach ($info->getValidationWarnings() as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - if (!$this->_displayValidationResults($err, $warn, true)) { - $this->ui->outputData($this->output, $command); - return $this->raiseError('CVS diff failed'); - } - - $info1 = $info->getFilelist(); - $files = $info1; - $cmd = "cvs"; - if (isset($options['quiet'])) { - $cmd .= ' -q'; - unset($options['quiet']); - } - - if (isset($options['reallyquiet'])) { - $cmd .= ' -Q'; - unset($options['reallyquiet']); - } - - if (isset($options['release'])) { - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']); - $cvstag = "RELEASE_$cvsversion"; - $options['revision'] = $cvstag; - unset($options['release']); - } - - $execute = true; - if (isset($options['dry-run'])) { - $execute = false; - unset($options['dry-run']); - } - - $cmd .= ' diff'; - // the rest of the options are passed right on to "cvs diff" - foreach ($options as $option => $optarg) { - $arg = $short = false; - if (isset($this->commands[$command]['options'][$option])) { - $arg = $this->commands[$command]['options'][$option]['arg']; - $short = $this->commands[$command]['options'][$option]['shortopt']; - } - $cmd .= $short ? " -$short" : " --$option"; - if ($arg && $optarg) { - $cmd .= ($short ? '' : '=') . escapeshellarg($optarg); - } - } - - foreach ($files as $file) { - $cmd .= ' ' . escapeshellarg($file['name']); - } - - if ($this->config->get('verbose') > 1) { - $this->output .= "+ $cmd\n"; - } - - if ($execute) { - $fp = popen($cmd, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - - $this->ui->outputData($this->output, $command); - return true; - } - - function doPackageDependencies($command, $options, $params) - { - // $params[0] -> the PEAR package to list its information - if (count($params) !== 1) { - return $this->raiseError("bad parameter(s), try \"help $command\""); - } - - $obj = &$this->getPackageFile($this->config, $this->_debug); - if (is_file($params[0]) || strpos($params[0], '.xml') > 0) { - $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); - } else { - $reg = $this->config->getRegistry(); - $info = $obj->fromArray($reg->packageInfo($params[0])); - } - - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $deps = $info->getDeps(); - if (is_array($deps)) { - if ($info->getPackagexmlVersion() == '1.0') { - $data = array( - 'caption' => 'Dependencies for pear/' . $info->getPackage(), - 'border' => true, - 'headline' => array("Required?", "Type", "Name", "Relation", "Version"), - ); - - foreach ($deps as $d) { - if (isset($d['optional'])) { - if ($d['optional'] == 'yes') { - $req = 'No'; - } else { - $req = 'Yes'; - } - } else { - $req = 'Yes'; - } - - if (isset($this->_deps_rel_trans[$d['rel']])) { - $rel = $this->_deps_rel_trans[$d['rel']]; - } else { - $rel = $d['rel']; - } - - if (isset($this->_deps_type_trans[$d['type']])) { - $type = ucfirst($this->_deps_type_trans[$d['type']]); - } else { - $type = $d['type']; - } - - if (isset($d['name'])) { - $name = $d['name']; - } else { - $name = ''; - } - - if (isset($d['version'])) { - $version = $d['version']; - } else { - $version = ''; - } - - $data['data'][] = array($req, $type, $name, $rel, $version); - } - } else { // package.xml 2.0 dependencies display - require_once 'PEAR/Dependency2.php'; - $deps = $info->getDependencies(); - $reg = &$this->config->getRegistry(); - if (is_array($deps)) { - $d = new PEAR_Dependency2($this->config, array(), ''); - $data = array( - 'caption' => 'Dependencies for ' . $info->getPackage(), - 'border' => true, - 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'), - ); - foreach ($deps as $type => $subd) { - $req = ($type == 'required') ? 'Yes' : 'No'; - if ($type == 'group') { - $group = $subd['attribs']['name']; - } else { - $group = ''; - } - - if (!isset($subd[0])) { - $subd = array($subd); - } - - foreach ($subd as $groupa) { - foreach ($groupa as $deptype => $depinfo) { - if ($deptype == 'attribs') { - continue; - } - - if ($deptype == 'pearinstaller') { - $deptype = 'pear Installer'; - } - - if (!isset($depinfo[0])) { - $depinfo = array($depinfo); - } - - foreach ($depinfo as $inf) { - $name = ''; - if (isset($inf['channel'])) { - $alias = $reg->channelAlias($inf['channel']); - if (!$alias) { - $alias = '(channel?) ' .$inf['channel']; - } - $name = $alias . '/'; - - } - if (isset($inf['name'])) { - $name .= $inf['name']; - } elseif (isset($inf['pattern'])) { - $name .= $inf['pattern']; - } else { - $name .= ''; - } - - if (isset($inf['uri'])) { - $name .= ' [' . $inf['uri'] . ']'; - } - - if (isset($inf['conflicts'])) { - $ver = 'conflicts'; - } else { - $ver = $d->_getExtraString($inf); - } - - $data['data'][] = array($req, ucfirst($deptype), $name, - $ver, $group); - } - } - } - } - } - } - - $this->ui->outputData($data, $command); - return true; - } - - // Fallback - $this->ui->outputData("This package does not have any dependencies.", $command); - } - - function doSign($command, $options, $params) - { - // should move most of this code into PEAR_Packager - // so it'll be easy to implement "pear package --sign" - if (count($params) !== 1) { - return $this->raiseError("bad parameter(s), try \"help $command\""); - } - - require_once 'System.php'; - require_once 'Archive/Tar.php'; - - if (!file_exists($params[0])) { - return $this->raiseError("file does not exist: $params[0]"); - } - - $obj = $this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $tar = new Archive_Tar($params[0]); - $tmpdir = System::mktemp('-d pearsign'); - if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) { - return $this->raiseError("failed to extract tar file"); - } - - if (file_exists("$tmpdir/package.sig")) { - return $this->raiseError("package already signed"); - } - - $packagexml = 'package.xml'; - if (file_exists("$tmpdir/package2.xml")) { - $packagexml = 'package2.xml'; - } - - if (file_exists("$tmpdir/package.sig")) { - unlink("$tmpdir/package.sig"); - } - - if (!file_exists("$tmpdir/$packagexml")) { - return $this->raiseError("Extracted file $tmpdir/$packagexml not found."); - } - - $input = $this->ui->userDialog($command, - array('GnuPG Passphrase'), - array('password')); - if (!isset($input[0])) { - //use empty passphrase - $input[0] = ''; - } - - $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null'; - $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w"); - if (!$gpg) { - return $this->raiseError("gpg command failed"); - } - - fwrite($gpg, "$input[0]\n"); - if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) { - return $this->raiseError("gpg sign failed"); - } - - if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) { - return $this->raiseError('failed adding signature to file'); - } - - $this->ui->outputData("Package signed.", $command); - return true; - } - - /** - * For unit testing purposes - */ - function &getInstaller(&$ui) - { - if (!class_exists('PEAR_Installer')) { - require_once 'PEAR/Installer.php'; - } - $a = &new PEAR_Installer($ui); - return $a; - } - - /** - * For unit testing purposes - */ - function &getCommandPackaging(&$ui, &$config) - { - if (!class_exists('PEAR_Command_Packaging')) { - if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) { - fclose($fp); - include_once 'PEAR/Command/Packaging.php'; - } - } - - if (class_exists('PEAR_Command_Packaging')) { - $a = &new PEAR_Command_Packaging($ui, $config); - } else { - $a = null; - } - - return $a; - } - - function doMakeRPM($command, $options, $params) - { - - // Check to see if PEAR_Command_Packaging is installed, and - // transparently switch to use the "make-rpm-spec" command from it - // instead, if it does. Otherwise, continue to use the old version - // of "makerpm" supplied with this package (PEAR). - $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config); - if ($packaging_cmd !== null) { - $this->ui->outputData('PEAR_Command_Packaging is installed; using '. - 'newer "make-rpm-spec" command instead'); - return $packaging_cmd->run('make-rpm-spec', $options, $params); - } - - $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '. - 'improved version is available via "pear make-rpm-spec", which '. - 'is available by installing PEAR_Command_Packaging'); - return true; - } - - function doConvert($command, $options, $params) - { - $packagexml = isset($params[0]) ? $params[0] : 'package.xml'; - $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) . - DIRECTORY_SEPARATOR . 'package2.xml'; - $pkg = &$this->getPackageFile($this->config, $this->_debug); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $warning) { - $this->ui->outputData($warning['message']); - } - } - return $this->raiseError($pf); - } - - if (is_a($pf, 'PEAR_PackageFile_v2')) { - $this->ui->outputData($packagexml . ' is already a package.xml version 2.0'); - return true; - } - - $gen = &$pf->getDefaultGenerator(); - $newpf = &$gen->toV2(); - $newpf->setPackagefile($newpackagexml); - $gen = &$newpf->getDefaultGenerator(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL); - $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml)); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($saved)) { - if (is_array($saved->getUserInfo())) { - foreach ($saved->getUserInfo() as $warning) { - $this->ui->outputData($warning['message']); - } - } - - $this->ui->outputData($saved->getMessage()); - return true; - } - - $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"'); - return true; - } -}PEAR-1.9.0/PEAR/Command/Pickle.xml100664 764 764 2233 100664 11344 - - Build PECL Package - doPackage - pi - - - Z - Do not gzip the package file - - - n - Print the name of the packaged file. - - - [descfile] -Creates a PECL package from its package2.xml file. - -An automatic conversion will be made to a package.xml 1.0 and written out to -disk in the current directory as "package.xml". Note that -only simple package.xml 2.0 will be converted. package.xml 2.0 with: - - - dependency types other than required/optional PECL package/ext/php/pearinstaller - - more than one extsrcrelease or zendextsrcrelease - - zendextbinrelease, extbinrelease, phprelease, or bundle release type - - dependency groups - - ignore tags in release filelist - - tasks other than replace - - custom roles - -will cause pickle to fail, and output an error message. If your package2.xml -uses any of these features, you are best off using PEAR_PackageFileManager to -generate both package.xml. - - -PEAR-1.9.0/PEAR/Command/Pickle.php100664 764 764 37207 100664 11364 - * @copyright 2005-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Pickle.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for login/logout - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 2005-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.1 - */ - -class PEAR_Command_Pickle extends PEAR_Command_Common -{ - var $commands = array( - 'pickle' => array( - 'summary' => 'Build PECL Package', - 'function' => 'doPackage', - 'shortcut' => 'pi', - 'options' => array( - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'Do not gzip the package file' - ), - 'showname' => array( - 'shortopt' => 'n', - 'doc' => 'Print the name of the packaged file.', - ), - ), - 'doc' => '[descfile] -Creates a PECL package from its package2.xml file. - -An automatic conversion will be made to a package.xml 1.0 and written out to -disk in the current directory as "package.xml". Note that -only simple package.xml 2.0 will be converted. package.xml 2.0 with: - - - dependency types other than required/optional PECL package/ext/php/pearinstaller - - more than one extsrcrelease or zendextsrcrelease - - zendextbinrelease, extbinrelease, phprelease, or bundle release type - - dependency groups - - ignore tags in release filelist - - tasks other than replace - - custom roles - -will cause pickle to fail, and output an error message. If your package2.xml -uses any of these features, you are best off using PEAR_PackageFileManager to -generate both package.xml. -' - ), - ); - - /** - * PEAR_Command_Package constructor. - * - * @access public - */ - function PEAR_Command_Pickle(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - /** - * For unit-testing ease - * - * @return PEAR_Packager - */ - function &getPackager() - { - if (!class_exists('PEAR_Packager')) { - require_once 'PEAR/Packager.php'; - } - - $a = &new PEAR_Packager; - return $a; - } - - /** - * For unit-testing ease - * - * @param PEAR_Config $config - * @param bool $debug - * @param string|null $tmpdir - * @return PEAR_PackageFile - */ - function &getPackageFile($config, $debug = false, $tmpdir = null) - { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - - $a = &new PEAR_PackageFile($config, $debug, $tmpdir); - $common = new PEAR_Common; - $common->ui = $this->ui; - $a->setLogger($common); - return $a; - } - - function doPackage($command, $options, $params) - { - $this->output = ''; - $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml'; - $packager = &$this->getPackager(); - if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) { - return $err; - } - - $compress = empty($options['nocompress']) ? true : false; - $result = $packager->package($pkginfofile, $compress, 'package.xml'); - if (PEAR::isError($result)) { - return $this->raiseError($result); - } - - // Don't want output, only the package file name just created - if (isset($options['showname'])) { - $this->ui->outputData($result, $command); - } - - return true; - } - - function _convertPackage($packagexml) - { - $pkg = &$this->getPackageFile($this->config); - $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); - if (!is_a($pf2, 'PEAR_PackageFile_v2')) { - return $this->raiseError('Cannot process "' . - $packagexml . '", is not a package.xml 2.0'); - } - - require_once 'PEAR/PackageFile/v1.php'; - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->config); - if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", is not an extension source package. Using a PEAR_PackageFileManager-based ' . - 'script is an option'); - } - - if (is_array($pf2->getUsesRole())) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' . - 'the convert command is an option'); - } - - if (is_array($pf2->getUsesTask())) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' . - 'the convert command is an option'); - } - - $deps = $pf2->getDependencies(); - if (isset($deps['group'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' . - 'or the convert command is an option'); - } - - if (isset($deps['required']['subpackage']) || - isset($deps['optional']['subpackage'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '. - 'script is an option'); - } - - if (isset($deps['required']['os'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains os dependencies. Using a PEAR_PackageFileManager-based '. - 'script is an option'); - } - - if (isset($deps['required']['arch'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains arch dependencies. Using a PEAR_PackageFileManager-based '. - 'script is an option'); - } - - $pf->setPackage($pf2->getPackage()); - $pf->setSummary($pf2->getSummary()); - $pf->setDescription($pf2->getDescription()); - foreach ($pf2->getMaintainers() as $maintainer) { - $pf->addMaintainer($maintainer['role'], $maintainer['handle'], - $maintainer['name'], $maintainer['email']); - } - - $pf->setVersion($pf2->getVersion()); - $pf->setDate($pf2->getDate()); - $pf->setLicense($pf2->getLicense()); - $pf->setState($pf2->getState()); - $pf->setNotes($pf2->getNotes()); - $pf->addPhpDep($deps['required']['php']['min'], 'ge'); - if (isset($deps['required']['php']['max'])) { - $pf->addPhpDep($deps['required']['php']['max'], 'le'); - } - - if (isset($deps['required']['package'])) { - if (!isset($deps['required']['package'][0])) { - $deps['required']['package'] = array($deps['required']['package']); - } - - foreach ($deps['required']['package'] as $dep) { - if (!isset($dep['channel'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains uri-based dependency on a package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } - - if ($dep['channel'] != 'pear.php.net' - && $dep['channel'] != 'pecl.php.net' - && $dep['channel'] != 'doc.php.net') { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains dependency on a non-standard channel package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } - - if (isset($dep['conflicts'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains conflicts dependency. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } - - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } - - if (isset($dep['min'])) { - $pf->addPackageDep($dep['name'], $dep['min'], 'ge'); - } - - if (isset($dep['max'])) { - $pf->addPackageDep($dep['name'], $dep['max'], 'le'); - } - } - } - - if (isset($deps['required']['extension'])) { - if (!isset($deps['required']['extension'][0])) { - $deps['required']['extension'] = array($deps['required']['extension']); - } - - foreach ($deps['required']['extension'] as $dep) { - if (isset($dep['conflicts'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains conflicts dependency. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } - - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } - - if (isset($dep['min'])) { - $pf->addExtensionDep($dep['name'], $dep['min'], 'ge'); - } - - if (isset($dep['max'])) { - $pf->addExtensionDep($dep['name'], $dep['max'], 'le'); - } - } - } - - if (isset($deps['optional']['package'])) { - if (!isset($deps['optional']['package'][0])) { - $deps['optional']['package'] = array($deps['optional']['package']); - } - - foreach ($deps['optional']['package'] as $dep) { - if (!isset($dep['channel'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains uri-based dependency on a package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } - - if ($dep['channel'] != 'pear.php.net' - && $dep['channel'] != 'pecl.php.net' - && $dep['channel'] != 'doc.php.net') { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains dependency on a non-standard channel package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } - - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } - - if (isset($dep['min'])) { - $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes'); - } - - if (isset($dep['max'])) { - $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes'); - } - } - } - - if (isset($deps['optional']['extension'])) { - if (!isset($deps['optional']['extension'][0])) { - $deps['optional']['extension'] = array($deps['optional']['extension']); - } - - foreach ($deps['optional']['extension'] as $dep) { - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } - - if (isset($dep['min'])) { - $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes'); - } - - if (isset($dep['max'])) { - $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes'); - } - } - } - - $contents = $pf2->getContents(); - $release = $pf2->getReleases(); - if (isset($releases[0])) { - return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' - . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' . - 'or the convert command is an option'); - } - - if ($configoptions = $pf2->getConfigureOptions()) { - foreach ($configoptions as $option) { - $default = isset($option['default']) ? $option['default'] : false; - $pf->addConfigureOption($option['name'], $option['prompt'], $default); - } - } - - if (isset($release['filelist']['ignore'])) { - return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' - . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' . - ' command is an option'); - } - - if (isset($release['filelist']['install']) && - !isset($release['filelist']['install'][0])) { - $release['filelist']['install'] = array($release['filelist']['install']); - } - - if (isset($contents['dir']['attribs']['baseinstalldir'])) { - $baseinstalldir = $contents['dir']['attribs']['baseinstalldir']; - } else { - $baseinstalldir = false; - } - - if (!isset($contents['dir']['file'][0])) { - $contents['dir']['file'] = array($contents['dir']['file']); - } - - foreach ($contents['dir']['file'] as $file) { - if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) { - $file['attribs']['baseinstalldir'] = $baseinstalldir; - } - - $processFile = $file; - unset($processFile['attribs']); - if (count($processFile)) { - foreach ($processFile as $name => $task) { - if ($name != $pf2->getTasksNs() . ':replace') { - return $this->raiseError('Cannot safely process "' . $packagexml . - '" contains tasks other than replace. Using a ' . - 'PEAR_PackageFileManager-based script is an option.'); - } - $file['attribs']['replace'][] = $task; - } - } - - if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains custom roles. Using a PEAR_PackageFileManager-based script ' . - 'or the convert command is an option'); - } - - if (isset($release['filelist']['install'])) { - foreach ($release['filelist']['install'] as $installas) { - if ($installas['attribs']['name'] == $file['attribs']['name']) { - $file['attribs']['install-as'] = $installas['attribs']['as']; - } - } - } - - $pf->addFile('/', $file['attribs']['name'], $file['attribs']); - } - - if ($pf2->getChangeLog()) { - $this->ui->outputData('WARNING: changelog is not translated to package.xml ' . - '1.0, use PEAR_PackageFileManager-based script if you need changelog-' . - 'translation for package.xml 1.0'); - } - - $gen = &$pf->getDefaultGenerator(); - $gen->toPackageFile('.'); - } -}PEAR-1.9.0/PEAR/Command/Registry.xml100664 764 764 3376 100664 11756 - - List Installed Packages In The Default Channel - doList - l - - - c - list installed packages from this channel - CHAN - - - a - list installed packages from all channels - - - i - output fully channel-aware data, even on failure - - - <package> -If invoked without parameters, this command lists the PEAR packages -installed in your php_dir ({config php_dir}). With a parameter, it -lists the files in a package. - - - - List Files In Installed Package - doFileList - fl - - <package> -List the files in an installed package. - - - - Shell Script Test - doShellTest - st - - <package> [[relation] version] -Tests if a package is installed in the system. Will exit(1) if it is not. - <relation> The version comparison operator. One of: - <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne - <version> The version to compare with - - - - Display information about a package - doInfo - in - - <package> -Displays information about a package. The package argument may be a -local package file, an URL to a package file, or the name of an -installed package. - -PEAR-1.9.0/PEAR/Command/Registry.php100664 764 764 132371 100664 12003 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Registry.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for registry manipulation - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Registry extends PEAR_Command_Common -{ - var $commands = array( - 'list' => array( - 'summary' => 'List Installed Packages In The Default Channel', - 'function' => 'doList', - 'shortcut' => 'l', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'list installed packages from this channel', - 'arg' => 'CHAN', - ), - 'allchannels' => array( - 'shortopt' => 'a', - 'doc' => 'list installed packages from all channels', - ), - 'channelinfo' => array( - 'shortopt' => 'i', - 'doc' => 'output fully channel-aware data, even on failure', - ), - ), - 'doc' => ' -If invoked without parameters, this command lists the PEAR packages -installed in your php_dir ({config php_dir}). With a parameter, it -lists the files in a package. -', - ), - 'list-files' => array( - 'summary' => 'List Files In Installed Package', - 'function' => 'doFileList', - 'shortcut' => 'fl', - 'options' => array(), - 'doc' => ' -List the files in an installed package. -' - ), - 'shell-test' => array( - 'summary' => 'Shell Script Test', - 'function' => 'doShellTest', - 'shortcut' => 'st', - 'options' => array(), - 'doc' => ' [[relation] version] -Tests if a package is installed in the system. Will exit(1) if it is not. - The version comparison operator. One of: - <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne - The version to compare with -'), - 'info' => array( - 'summary' => 'Display information about a package', - 'function' => 'doInfo', - 'shortcut' => 'in', - 'options' => array(), - 'doc' => ' -Displays information about a package. The package argument may be a -local package file, an URL to a package file, or the name of an -installed package.' - ) - ); - - /** - * PEAR_Command_Registry constructor. - * - * @access public - */ - function PEAR_Command_Registry(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function _sortinfo($a, $b) - { - $apackage = isset($a['package']) ? $a['package'] : $a['name']; - $bpackage = isset($b['package']) ? $b['package'] : $b['name']; - return strcmp($apackage, $bpackage); - } - - function doList($command, $options, $params) - { - $reg = &$this->config->getRegistry(); - $channelinfo = isset($options['channelinfo']); - if (isset($options['allchannels']) && !$channelinfo) { - return $this->doListAll($command, array(), $params); - } - - if (isset($options['allchannels']) && $channelinfo) { - // allchannels with $channelinfo - unset($options['allchannels']); - $channels = $reg->getChannels(); - $errors = array(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - foreach ($channels as $channel) { - $options['channel'] = $channel->getName(); - $ret = $this->doList($command, $options, $params); - - if (PEAR::isError($ret)) { - $errors[] = $ret; - } - } - - PEAR::staticPopErrorHandling(); - if (count($errors)) { - // for now, only give first error - return PEAR::raiseError($errors[0]); - } - - return true; - } - - if (count($params) === 1) { - return $this->doFileList($command, $options, $params); - } - - if (isset($options['channel'])) { - if (!$reg->channelExists($options['channel'])) { - return $this->raiseError('Channel "' . $options['channel'] .'" does not exist'); - } - - $channel = $reg->channelName($options['channel']); - } else { - $channel = $this->config->get('default_channel'); - } - - $installed = $reg->packageInfo(null, null, $channel); - usort($installed, array(&$this, '_sortinfo')); - - $data = array( - 'caption' => 'Installed packages, channel ' . - $channel . ':', - 'border' => true, - 'headline' => array('Package', 'Version', 'State'), - 'channel' => $channel, - ); - if ($channelinfo) { - $data['headline'] = array('Channel', 'Package', 'Version', 'State'); - } - - if (count($installed) && !isset($data['data'])) { - $data['data'] = array(); - } - - foreach ($installed as $package) { - $pobj = $reg->getPackage(isset($package['package']) ? - $package['package'] : $package['name'], $channel); - if ($channelinfo) { - $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(), - $pobj->getState() ? $pobj->getState() : null); - } else { - $packageinfo = array($pobj->getPackage(), $pobj->getVersion(), - $pobj->getState() ? $pobj->getState() : null); - } - $data['data'][] = $packageinfo; - } - - if (count($installed) === 0) { - if (!$channelinfo) { - $data = '(no packages installed from channel ' . $channel . ')'; - } else { - $data = array( - 'caption' => 'Installed packages, channel ' . - $channel . ':', - 'border' => true, - 'channel' => $channel, - 'data' => array(array('(no packages installed)')), - ); - } - } - - $this->ui->outputData($data, $command); - return true; - } - - function doListAll($command, $options, $params) - { - // This duplicate code is deprecated over - // list --channelinfo, which gives identical - // output for list and list --allchannels. - $reg = &$this->config->getRegistry(); - $installed = $reg->packageInfo(null, null, null); - foreach ($installed as $channel => $packages) { - usort($packages, array($this, '_sortinfo')); - $data = array( - 'caption' => 'Installed packages, channel ' . $channel . ':', - 'border' => true, - 'headline' => array('Package', 'Version', 'State'), - 'channel' => $channel - ); - - foreach ($packages as $package) { - $p = isset($package['package']) ? $package['package'] : $package['name']; - $pobj = $reg->getPackage($p, $channel); - $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(), - $pobj->getState() ? $pobj->getState() : null); - } - - // Adds a blank line after each section - $data['data'][] = array(); - - if (count($packages) === 0) { - $data = array( - 'caption' => 'Installed packages, channel ' . $channel . ':', - 'border' => true, - 'data' => array(array('(no packages installed)'), array()), - 'channel' => $channel - ); - } - $this->ui->outputData($data, $command); - } - return true; - } - - function doFileList($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError('list-files expects 1 parameter'); - } - - $reg = &$this->config->getRegistry(); - $fp = false; - if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))) { - if ($fp) { - fclose($fp); - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - - $pkg = &new PEAR_PackageFile($this->config, $this->_debug); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); - PEAR::staticPopErrorHandling(); - $headings = array('Package File', 'Install Path'); - $installed = false; - } else { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($parsed)) { - return $this->raiseError($parsed); - } - - $info = &$reg->getPackage($parsed['package'], $parsed['channel']); - $headings = array('Type', 'Install Path'); - $installed = true; - } - - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - if ($info === null) { - return $this->raiseError("`$params[0]' not installed"); - } - - $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ? - $info->getFilelist() : $info->getContents(); - if ($installed) { - $caption = 'Installed Files For ' . $params[0]; - } else { - $caption = 'Contents of ' . basename($params[0]); - } - - $data = array( - 'caption' => $caption, - 'border' => true, - 'headline' => $headings); - if ($info->getPackagexmlVersion() == '1.0' || $installed) { - foreach ($list as $file => $att) { - if ($installed) { - if (empty($att['installed_as'])) { - continue; - } - $data['data'][] = array($att['role'], $att['installed_as']); - } else { - if (isset($att['baseinstalldir']) && !in_array($att['role'], - array('test', 'data', 'doc'))) { - $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR . - $file; - } else { - $dest = $file; - } - switch ($att['role']) { - case 'test': - case 'data': - case 'doc': - $role = $att['role']; - if ($role == 'test') { - $role .= 's'; - } - $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR . - $info->getPackage() . DIRECTORY_SEPARATOR . $dest; - break; - case 'php': - default: - $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR . - $dest; - } - $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; - $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), - array(DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR), - $dest); - $file = preg_replace('!/+!', '/', $file); - $data['data'][] = array($file, $dest); - } - } - } else { // package.xml 2.0, not installed - if (!isset($list['dir']['file'][0])) { - $list['dir']['file'] = array($list['dir']['file']); - } - - foreach ($list['dir']['file'] as $att) { - $att = $att['attribs']; - $file = $att['name']; - $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config); - $role->setup($this, $info, $att, $file); - if (!$role->isInstallable()) { - $dest = '(not installable)'; - } else { - $dest = $role->processInstallation($info, $att, $file, ''); - if (PEAR::isError($dest)) { - $dest = '(Unknown role "' . $att['role'] . ')'; - } else { - list(,, $dest) = $dest; - } - } - $data['data'][] = array($file, $dest); - } - } - - $this->ui->outputData($data, $command); - return true; - } - - function doShellTest($command, $options, $params) - { - if (count($params) < 1) { - return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]'); - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $reg = &$this->config->getRegistry(); - $info = $reg->parsePackageName($params[0], $this->config->get('default_channel')); - if (PEAR::isError($info)) { - exit(1); // invalid package name - } - - $package = $info['package']; - $channel = $info['channel']; - // "pear shell-test Foo" - if (!$reg->packageExists($package, $channel)) { - if ($channel == 'pecl.php.net') { - if ($reg->packageExists($package, 'pear.php.net')) { - $channel = 'pear.php.net'; // magically change channels for extensions - } - } - } - - if (count($params) === 1) { - if (!$reg->packageExists($package, $channel)) { - exit(1); - } - // "pear shell-test Foo 1.0" - } elseif (count($params) === 2) { - $v = $reg->packageInfo($package, 'version', $channel); - if (!$v || !version_compare("$v", "{$params[1]}", "ge")) { - exit(1); - } - // "pear shell-test Foo ge 1.0" - } elseif (count($params) === 3) { - $v = $reg->packageInfo($package, 'version', $channel); - if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) { - exit(1); - } - } else { - PEAR::staticPopErrorHandling(); - $this->raiseError("$command: expects 1 to 3 parameters"); - exit(1); - } - } - - function doInfo($command, $options, $params) - { - if (count($params) !== 1) { - return $this->raiseError('pear info expects 1 parameter'); - } - - $info = $fp = false; - $reg = &$this->config->getRegistry(); - if ((file_exists($params[0]) && is_file($params[0]) && !is_dir($params[0])) || $fp = @fopen($params[0], 'r')) { - if ($fp) { - fclose($fp); - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - - $pkg = &new PEAR_PackageFile($this->config, $this->_debug); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($obj)) { - $uinfo = $obj->getUserInfo(); - if (is_array($uinfo)) { - foreach ($uinfo as $message) { - if (is_array($message)) { - $message = $message['message']; - } - $this->ui->outputData($message); - } - } - - return $this->raiseError($obj); - } - - if ($obj->getPackagexmlVersion() != '1.0') { - return $this->_doInfo2($command, $options, $params, $obj, false); - } - - $info = $obj->toArray(); - } else { - $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); - if (PEAR::isError($parsed)) { - return $this->raiseError($parsed); - } - - $package = $parsed['package']; - $channel = $parsed['channel']; - $info = $reg->packageInfo($package, null, $channel); - if (isset($info['old'])) { - $obj = $reg->getPackage($package, $channel); - return $this->_doInfo2($command, $options, $params, $obj, true); - } - } - - if (PEAR::isError($info)) { - return $info; - } - - if (empty($info)) { - $this->raiseError("No information found for `$params[0]'"); - return; - } - - unset($info['filelist']); - unset($info['dirtree']); - unset($info['changelog']); - if (isset($info['xsdversion'])) { - $info['package.xml version'] = $info['xsdversion']; - unset($info['xsdversion']); - } - - if (isset($info['packagerversion'])) { - $info['packaged with PEAR version'] = $info['packagerversion']; - unset($info['packagerversion']); - } - - $keys = array_keys($info); - $longtext = array('description', 'summary'); - foreach ($keys as $key) { - if (is_array($info[$key])) { - switch ($key) { - case 'maintainers': { - $i = 0; - $mstr = ''; - foreach ($info[$key] as $m) { - if ($i++ > 0) { - $mstr .= "\n"; - } - $mstr .= $m['name'] . " <"; - if (isset($m['email'])) { - $mstr .= $m['email']; - } else { - $mstr .= $m['handle'] . '@php.net'; - } - $mstr .= "> ($m[role])"; - } - $info[$key] = $mstr; - break; - } - case 'release_deps': { - $i = 0; - $dstr = ''; - foreach ($info[$key] as $d) { - if (isset($this->_deps_rel_trans[$d['rel']])) { - $rel = $this->_deps_rel_trans[$d['rel']]; - } else { - $rel = $d['rel']; - } - if (isset($this->_deps_type_trans[$d['type']])) { - $type = ucfirst($this->_deps_type_trans[$d['type']]); - } else { - $type = $d['type']; - } - if (isset($d['name'])) { - $name = $d['name'] . ' '; - } else { - $name = ''; - } - if (isset($d['version'])) { - $version = $d['version'] . ' '; - } else { - $version = ''; - } - if (isset($d['optional']) && $d['optional'] == 'yes') { - $optional = ' (optional)'; - } else { - $optional = ''; - } - $dstr .= "$type $name$rel $version$optional\n"; - } - $info[$key] = $dstr; - break; - } - case 'provides' : { - $debug = $this->config->get('verbose'); - if ($debug < 2) { - $pstr = 'Classes: '; - } else { - $pstr = ''; - } - $i = 0; - foreach ($info[$key] as $p) { - if ($debug < 2 && $p['type'] != "class") { - continue; - } - // Only print classes when verbosity mode is < 2 - if ($debug < 2) { - if ($i++ > 0) { - $pstr .= ", "; - } - $pstr .= $p['name']; - } else { - if ($i++ > 0) { - $pstr .= "\n"; - } - $pstr .= ucfirst($p['type']) . " " . $p['name']; - if (isset($p['explicit']) && $p['explicit'] == 1) { - $pstr .= " (explicit)"; - } - } - } - $info[$key] = $pstr; - break; - } - case 'configure_options' : { - foreach ($info[$key] as $i => $p) { - $info[$key][$i] = array_map(null, array_keys($p), array_values($p)); - $info[$key][$i] = array_map(create_function('$a', - 'return join(" = ",$a);'), $info[$key][$i]); - $info[$key][$i] = implode(', ', $info[$key][$i]); - } - $info[$key] = implode("\n", $info[$key]); - break; - } - default: { - $info[$key] = implode(", ", $info[$key]); - break; - } - } - } - - if ($key == '_lastmodified') { - $hdate = date('Y-m-d', $info[$key]); - unset($info[$key]); - $info['Last Modified'] = $hdate; - } elseif ($key == '_lastversion') { - $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -'; - unset($info[$key]); - } else { - $info[$key] = trim($info[$key]); - if (in_array($key, $longtext)) { - $info[$key] = preg_replace('/ +/', ' ', $info[$key]); - } - } - } - - $caption = 'About ' . $info['package'] . '-' . $info['version']; - $data = array( - 'caption' => $caption, - 'border' => true); - foreach ($info as $key => $value) { - $key = ucwords(trim(str_replace('_', ' ', $key))); - $data['data'][] = array($key, $value); - } - $data['raw'] = $info; - - $this->ui->outputData($data, 'package-info'); - } - - /** - * @access private - */ - function _doInfo2($command, $options, $params, &$obj, $installed) - { - $reg = &$this->config->getRegistry(); - $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' . - $obj->getVersion(); - $data = array( - 'caption' => $caption, - 'border' => true); - switch ($obj->getPackageType()) { - case 'php' : - $release = 'PEAR-style PHP-based Package'; - break; - case 'extsrc' : - $release = 'PECL-style PHP extension (source code)'; - break; - case 'zendextsrc' : - $release = 'PECL-style Zend extension (source code)'; - break; - case 'extbin' : - $release = 'PECL-style PHP extension (binary)'; - break; - case 'zendextbin' : - $release = 'PECL-style Zend extension (binary)'; - break; - case 'bundle' : - $release = 'Package bundle (collection of packages)'; - break; - } - $extends = $obj->getExtends(); - $extends = $extends ? - $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage(); - if ($src = $obj->getSourcePackage()) { - $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')'; - } - - $info = array( - 'Release Type' => $release, - 'Name' => $extends, - 'Channel' => $obj->getChannel(), - 'Summary' => preg_replace('/ +/', ' ', $obj->getSummary()), - 'Description' => preg_replace('/ +/', ' ', $obj->getDescription()), - ); - $info['Maintainers'] = ''; - foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { - $leads = $obj->{"get{$role}s"}(); - if (!$leads) { - continue; - } - - if (isset($leads['active'])) { - $leads = array($leads); - } - - foreach ($leads as $lead) { - if (!empty($info['Maintainers'])) { - $info['Maintainers'] .= "\n"; - } - - $active = $lead['active'] == 'no' ? ', inactive' : ''; - $info['Maintainers'] .= $lead['name'] . ' <'; - $info['Maintainers'] .= $lead['email'] . "> ($role$active)"; - } - } - - $info['Release Date'] = $obj->getDate(); - if ($time = $obj->getTime()) { - $info['Release Date'] .= ' ' . $time; - } - - $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')'; - $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')'; - $info['License'] = $obj->getLicense(); - $uri = $obj->getLicenseLocation(); - if ($uri) { - if (isset($uri['uri'])) { - $info['License'] .= ' (' . $uri['uri'] . ')'; - } else { - $extra = $obj->getInstalledLocation($info['filesource']); - if ($extra) { - $info['License'] .= ' (' . $uri['filesource'] . ')'; - } - } - } - - $info['Release Notes'] = $obj->getNotes(); - if ($compat = $obj->getCompatible()) { - if (!isset($compat[0])) { - $compat = array($compat); - } - - $info['Compatible with'] = ''; - foreach ($compat as $package) { - $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] . - "\nVersions >= " . $package['min'] . ', <= ' . $package['max']; - if (isset($package['exclude'])) { - if (is_array($package['exclude'])) { - $package['exclude'] = implode(', ', $package['exclude']); - } - - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - $info['Not Compatible with'] .= $package['channel'] . '/' . - $package['name'] . "\nVersions " . $package['exclude']; - } - } - } - - $usesrole = $obj->getUsesrole(); - if ($usesrole) { - if (!isset($usesrole[0])) { - $usesrole = array($usesrole); - } - - foreach ($usesrole as $roledata) { - if (isset($info['Uses Custom Roles'])) { - $info['Uses Custom Roles'] .= "\n"; - } else { - $info['Uses Custom Roles'] = ''; - } - - if (isset($roledata['package'])) { - $rolepackage = $reg->parsedPackageNameToString($roledata, true); - } else { - $rolepackage = $roledata['uri']; - } - $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')'; - } - } - - $usestask = $obj->getUsestask(); - if ($usestask) { - if (!isset($usestask[0])) { - $usestask = array($usestask); - } - - foreach ($usestask as $taskdata) { - if (isset($info['Uses Custom Tasks'])) { - $info['Uses Custom Tasks'] .= "\n"; - } else { - $info['Uses Custom Tasks'] = ''; - } - - if (isset($taskdata['package'])) { - $taskpackage = $reg->parsedPackageNameToString($taskdata, true); - } else { - $taskpackage = $taskdata['uri']; - } - $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')'; - } - } - - $deps = $obj->getDependencies(); - $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min']; - if (isset($deps['required']['php']['max'])) { - $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n"; - } else { - $info['Required Dependencies'] .= "\n"; - } - - if (isset($deps['required']['php']['exclude'])) { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - - if (is_array($deps['required']['php']['exclude'])) { - $deps['required']['php']['exclude'] = - implode(', ', $deps['required']['php']['exclude']); - } - $info['Not Compatible with'] .= "PHP versions\n " . - $deps['required']['php']['exclude']; - } - - $info['Required Dependencies'] .= 'PEAR installer version'; - if (isset($deps['required']['pearinstaller']['max'])) { - $info['Required Dependencies'] .= 's ' . - $deps['required']['pearinstaller']['min'] . '-' . - $deps['required']['pearinstaller']['max']; - } else { - $info['Required Dependencies'] .= ' ' . - $deps['required']['pearinstaller']['min'] . ' or newer'; - } - - if (isset($deps['required']['pearinstaller']['exclude'])) { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - - if (is_array($deps['required']['pearinstaller']['exclude'])) { - $deps['required']['pearinstaller']['exclude'] = - implode(', ', $deps['required']['pearinstaller']['exclude']); - } - $info['Not Compatible with'] .= "PEAR installer\n Versions " . - $deps['required']['pearinstaller']['exclude']; - } - - foreach (array('Package', 'Extension') as $type) { - $index = strtolower($type); - if (isset($deps['required'][$index])) { - if (isset($deps['required'][$index]['name'])) { - $deps['required'][$index] = array($deps['required'][$index]); - } - - foreach ($deps['required'][$index] as $package) { - if (isset($package['conflicts'])) { - $infoindex = 'Not Compatible with'; - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - } else { - $infoindex = 'Required Dependencies'; - $info[$infoindex] .= "\n"; - } - - if ($index == 'extension') { - $name = $package['name']; - } else { - if (isset($package['channel'])) { - $name = $package['channel'] . '/' . $package['name']; - } else { - $name = '__uri/' . $package['name'] . ' (static URI)'; - } - } - - $info[$infoindex] .= "$type $name"; - if (isset($package['uri'])) { - $info[$infoindex] .= "\n Download URI: $package[uri]"; - continue; - } - - if (isset($package['max']) && isset($package['min'])) { - $info[$infoindex] .= " \n Versions " . - $package['min'] . '-' . $package['max']; - } elseif (isset($package['min'])) { - $info[$infoindex] .= " \n Version " . - $package['min'] . ' or newer'; - } elseif (isset($package['max'])) { - $info[$infoindex] .= " \n Version " . - $package['max'] . ' or older'; - } - - if (isset($package['recommended'])) { - $info[$infoindex] .= "\n Recommended version: $package[recommended]"; - } - - if (isset($package['exclude'])) { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - - if (is_array($package['exclude'])) { - $package['exclude'] = implode(', ', $package['exclude']); - } - - $package['package'] = $package['name']; // for parsedPackageNameToString - if (isset($package['conflicts'])) { - $info['Not Compatible with'] .= '=> except '; - } - $info['Not Compatible with'] .= 'Package ' . - $reg->parsedPackageNameToString($package, true); - $info['Not Compatible with'] .= "\n Versions " . $package['exclude']; - } - } - } - } - - if (isset($deps['required']['os'])) { - if (isset($deps['required']['os']['name'])) { - $dep['required']['os']['name'] = array($dep['required']['os']['name']); - } - - foreach ($dep['required']['os'] as $os) { - if (isset($os['conflicts']) && $os['conflicts'] == 'yes') { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - $info['Not Compatible with'] .= "$os[name] Operating System"; - } else { - $info['Required Dependencies'] .= "\n"; - $info['Required Dependencies'] .= "$os[name] Operating System"; - } - } - } - - if (isset($deps['required']['arch'])) { - if (isset($deps['required']['arch']['pattern'])) { - $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']); - } - - foreach ($dep['required']['arch'] as $os) { - if (isset($os['conflicts']) && $os['conflicts'] == 'yes') { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'"; - } else { - $info['Required Dependencies'] .= "\n"; - $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'"; - } - } - } - - if (isset($deps['optional'])) { - foreach (array('Package', 'Extension') as $type) { - $index = strtolower($type); - if (isset($deps['optional'][$index])) { - if (isset($deps['optional'][$index]['name'])) { - $deps['optional'][$index] = array($deps['optional'][$index]); - } - - foreach ($deps['optional'][$index] as $package) { - if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { - $infoindex = 'Not Compatible with'; - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - } else { - $infoindex = 'Optional Dependencies'; - if (!isset($info['Optional Dependencies'])) { - $info['Optional Dependencies'] = ''; - } else { - $info['Optional Dependencies'] .= "\n"; - } - } - - if ($index == 'extension') { - $name = $package['name']; - } else { - if (isset($package['channel'])) { - $name = $package['channel'] . '/' . $package['name']; - } else { - $name = '__uri/' . $package['name'] . ' (static URI)'; - } - } - - $info[$infoindex] .= "$type $name"; - if (isset($package['uri'])) { - $info[$infoindex] .= "\n Download URI: $package[uri]"; - continue; - } - - if ($infoindex == 'Not Compatible with') { - // conflicts is only used to say that all versions conflict - continue; - } - - if (isset($package['max']) && isset($package['min'])) { - $info[$infoindex] .= " \n Versions " . - $package['min'] . '-' . $package['max']; - } elseif (isset($package['min'])) { - $info[$infoindex] .= " \n Version " . - $package['min'] . ' or newer'; - } elseif (isset($package['max'])) { - $info[$infoindex] .= " \n Version " . - $package['min'] . ' or older'; - } - - if (isset($package['recommended'])) { - $info[$infoindex] .= "\n Recommended version: $package[recommended]"; - } - - if (isset($package['exclude'])) { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info['Not Compatible with'] .= "\n"; - } - - if (is_array($package['exclude'])) { - $package['exclude'] = implode(', ', $package['exclude']); - } - - $info['Not Compatible with'] .= "Package $package\n Versions " . - $package['exclude']; - } - } - } - } - } - - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - foreach ($deps['group'] as $group) { - $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint']; - $groupindex = $group['attribs']['name'] . ' Contents'; - $info[$groupindex] = ''; - foreach (array('Package', 'Extension') as $type) { - $index = strtolower($type); - if (isset($group[$index])) { - if (isset($group[$index]['name'])) { - $group[$index] = array($group[$index]); - } - - foreach ($group[$index] as $package) { - if (!empty($info[$groupindex])) { - $info[$groupindex] .= "\n"; - } - - if ($index == 'extension') { - $name = $package['name']; - } else { - if (isset($package['channel'])) { - $name = $package['channel'] . '/' . $package['name']; - } else { - $name = '__uri/' . $package['name'] . ' (static URI)'; - } - } - - if (isset($package['uri'])) { - if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { - $info[$groupindex] .= "Not Compatible with $type $name"; - } else { - $info[$groupindex] .= "$type $name"; - } - - $info[$groupindex] .= "\n Download URI: $package[uri]"; - continue; - } - - if (isset($package['conflicts']) && $package['conflicts'] == 'yes') { - $info[$groupindex] .= "Not Compatible with $type $name"; - continue; - } - - $info[$groupindex] .= "$type $name"; - if (isset($package['max']) && isset($package['min'])) { - $info[$groupindex] .= " \n Versions " . - $package['min'] . '-' . $package['max']; - } elseif (isset($package['min'])) { - $info[$groupindex] .= " \n Version " . - $package['min'] . ' or newer'; - } elseif (isset($package['max'])) { - $info[$groupindex] .= " \n Version " . - $package['min'] . ' or older'; - } - - if (isset($package['recommended'])) { - $info[$groupindex] .= "\n Recommended version: $package[recommended]"; - } - - if (isset($package['exclude'])) { - if (!isset($info['Not Compatible with'])) { - $info['Not Compatible with'] = ''; - } else { - $info[$groupindex] .= "Not Compatible with\n"; - } - - if (is_array($package['exclude'])) { - $package['exclude'] = implode(', ', $package['exclude']); - } - $info[$groupindex] .= " Package $package\n Versions " . - $package['exclude']; - } - } - } - } - } - } - - if ($obj->getPackageType() == 'bundle') { - $info['Bundled Packages'] = ''; - foreach ($obj->getBundledPackages() as $package) { - if (!empty($info['Bundled Packages'])) { - $info['Bundled Packages'] .= "\n"; - } - - if (isset($package['uri'])) { - $info['Bundled Packages'] .= '__uri/' . $package['name']; - $info['Bundled Packages'] .= "\n (URI: $package[uri]"; - } else { - $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name']; - } - } - } - - $info['package.xml version'] = '2.0'; - if ($installed) { - if ($obj->getLastModified()) { - $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified()); - } - - $v = $obj->getLastInstalledVersion(); - $info['Previous Installed Version'] = $v ? $v : '- None -'; - } - - foreach ($info as $key => $value) { - $data['data'][] = array($key, $value); - } - - $data['raw'] = $obj->getArray(); // no validation needed - $this->ui->outputData($data, 'package-info'); - } -}PEAR-1.9.0/PEAR/Command/Remote.xml100664 764 764 6357 100664 11403 - - Information About Remote Packages - doRemoteInfo - ri - - <package> -Get details on a package from the server. - - - List Available Upgrades - doListUpgrades - lu - - - i - output fully channel-aware data, even on failure - - - [preferred_state] -List releases on the server of packages you have installed where -a newer version is available with the same release state (stable etc.) -or the state passed as the second parameter. - - - List Remote Packages - doRemoteList - rl - - - c - specify a channel other than the default channel - CHAN - - - -Lists the packages available on the configured server along with the -latest stable release of each package. - - - Search remote package database - doSearch - sp - - - c - specify a channel other than the default channel - CHAN - - - a - search packages from all known channels - - - i - output fully channel-aware data, even on failure - - - [packagename] [packageinfo] -Lists all packages which match the search parameters. The first -parameter is a fragment of a packagename. The default channel -will be used unless explicitly overridden. The second parameter -will be used to match any portion of the summary/description - - - List All Packages - doListAll - la - - - c - specify a channel other than the default channel - CHAN - - - i - output fully channel-aware data, even on failure - - - -Lists the packages available on the configured server along with the -latest stable release of each package. - - - Download Package - doDownload - d - - - Z - download an uncompressed (.tar) file - - - <package>... -Download package tarballs. The files will be named as suggested by the -server, for example if you download the DB package and the latest stable -version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz. - - - Clear Web Services Cache - doClearCache - cc - - -Clear the XML-RPC/REST cache. See also the cache_ttl configuration -parameter. - - -PEAR-1.9.0/PEAR/Command/Remote.php100664 764 764 72576 100664 11420 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Remote.php 287477 2009-08-19 14:19:43Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; -require_once 'PEAR/REST.php'; - -/** - * PEAR commands for remote server querying - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Remote extends PEAR_Command_Common -{ - var $commands = array( - 'remote-info' => array( - 'summary' => 'Information About Remote Packages', - 'function' => 'doRemoteInfo', - 'shortcut' => 'ri', - 'options' => array(), - 'doc' => ' -Get details on a package from the server.', - ), - 'list-upgrades' => array( - 'summary' => 'List Available Upgrades', - 'function' => 'doListUpgrades', - 'shortcut' => 'lu', - 'options' => array( - 'channelinfo' => array( - 'shortopt' => 'i', - 'doc' => 'output fully channel-aware data, even on failure', - ), - ), - 'doc' => '[preferred_state] -List releases on the server of packages you have installed where -a newer version is available with the same release state (stable etc.) -or the state passed as the second parameter.' - ), - 'remote-list' => array( - 'summary' => 'List Remote Packages', - 'function' => 'doRemoteList', - 'shortcut' => 'rl', - 'options' => array( - 'channel' => - array( - 'shortopt' => 'c', - 'doc' => 'specify a channel other than the default channel', - 'arg' => 'CHAN', - ) - ), - 'doc' => ' -Lists the packages available on the configured server along with the -latest stable release of each package.', - ), - 'search' => array( - 'summary' => 'Search remote package database', - 'function' => 'doSearch', - 'shortcut' => 'sp', - 'options' => array( - 'channel' => - array( - 'shortopt' => 'c', - 'doc' => 'specify a channel other than the default channel', - 'arg' => 'CHAN', - ), - 'allchannels' => array( - 'shortopt' => 'a', - 'doc' => 'search packages from all known channels', - ), - 'channelinfo' => array( - 'shortopt' => 'i', - 'doc' => 'output fully channel-aware data, even on failure', - ), - ), - 'doc' => '[packagename] [packageinfo] -Lists all packages which match the search parameters. The first -parameter is a fragment of a packagename. The default channel -will be used unless explicitly overridden. The second parameter -will be used to match any portion of the summary/description', - ), - 'list-all' => array( - 'summary' => 'List All Packages', - 'function' => 'doListAll', - 'shortcut' => 'la', - 'options' => array( - 'channel' => - array( - 'shortopt' => 'c', - 'doc' => 'specify a channel other than the default channel', - 'arg' => 'CHAN', - ), - 'channelinfo' => array( - 'shortopt' => 'i', - 'doc' => 'output fully channel-aware data, even on failure', - ), - ), - 'doc' => ' -Lists the packages available on the configured server along with the -latest stable release of each package.', - ), - 'download' => array( - 'summary' => 'Download Package', - 'function' => 'doDownload', - 'shortcut' => 'd', - 'options' => array( - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'download an uncompressed (.tar) file', - ), - ), - 'doc' => '... -Download package tarballs. The files will be named as suggested by the -server, for example if you download the DB package and the latest stable -version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.', - ), - 'clear-cache' => array( - 'summary' => 'Clear Web Services Cache', - 'function' => 'doClearCache', - 'shortcut' => 'cc', - 'options' => array(), - 'doc' => ' -Clear the XML-RPC/REST cache. See also the cache_ttl configuration -parameter. -', - ), - ); - - /** - * PEAR_Command_Remote constructor. - * - * @access public - */ - function PEAR_Command_Remote(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function _checkChannelForStatus($channel, $chan) - { - if (PEAR::isError($chan)) { - $this->raiseError($chan); - } - if (!is_a($chan, 'PEAR_ChannelFile')) { - return $this->raiseError('Internal corruption error: invalid channel "' . - $channel . '"'); - } - $rest = new PEAR_REST($this->config); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $mirror = $this->config->get('preferred_mirror', null, - $channel); - $a = $rest->downloadHttp('http://' . $channel . - '/channel.xml', $chan->lastModified()); - PEAR::staticPopErrorHandling(); - if (!PEAR::isError($a) && $a) { - $this->ui->outputData('WARNING: channel "' . $channel . '" has ' . - 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $channel . - '" to update'); - } - } - - function doRemoteInfo($command, $options, $params) - { - if (sizeof($params) != 1) { - return $this->raiseError("$command expects one param: the remote package name"); - } - $savechannel = $channel = $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - $package = $params[0]; - $parsed = $reg->parsePackageName($package, $channel); - if (PEAR::isError($parsed)) { - return $this->raiseError('Invalid package name "' . $package . '"'); - } - - $channel = $parsed['channel']; - $this->config->set('default_channel', $channel); - $chan = $reg->getChannel($channel); - if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { - return $e; - } - - $mirror = $this->config->get('preferred_mirror'); - if ($chan->supportsREST($mirror) && $base = $chan->getBaseURL('REST1.0', $mirror)) { - $rest = &$this->config->getREST('1.0', array()); - $info = $rest->packageInfo($base, $parsed['package'], $channel); - } - - if (!isset($info)) { - return $this->raiseError('No supported protocol was found'); - } - - if (PEAR::isError($info)) { - $this->config->set('default_channel', $savechannel); - return $this->raiseError($info); - } - - if (!isset($info['name'])) { - return $this->raiseError('No remote package "' . $package . '" was found'); - } - - $installed = $reg->packageInfo($info['name'], null, $channel); - $info['installed'] = $installed['version'] ? $installed['version'] : '- no -'; - if (is_array($info['installed'])) { - $info['installed'] = $info['installed']['release']; - } - - $this->ui->outputData($info, $command); - $this->config->set('default_channel', $savechannel); - - return true; - } - - function doRemoteList($command, $options, $params) - { - $savechannel = $channel = $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - if (isset($options['channel'])) { - $channel = $options['channel']; - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - $this->config->set('default_channel', $channel); - } - - $chan = $reg->getChannel($channel); - if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { - return $e; - } - - $list_options = false; - if ($this->config->get('preferred_state') == 'stable') { - $list_options = true; - } - - $available = array(); - if ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror')) - ) { - // use faster list-all if available - $rest = &$this->config->getREST('1.1', array()); - $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName()); - } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { - $rest = &$this->config->getREST('1.0', array()); - $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName()); - } - - if (PEAR::isError($available)) { - $this->config->set('default_channel', $savechannel); - return $this->raiseError($available); - } - - $i = $j = 0; - $data = array( - 'caption' => 'Channel ' . $channel . ' Available packages:', - 'border' => true, - 'headline' => array('Package', 'Version'), - 'channel' => $channel - ); - - if (count($available) == 0) { - $data = '(no packages available yet)'; - } else { - foreach ($available as $name => $info) { - $version = (isset($info['stable']) && $info['stable']) ? $info['stable'] : '-n/a-'; - $data['data'][] = array($name, $version); - } - } - $this->ui->outputData($data, $command); - $this->config->set('default_channel', $savechannel); - return true; - } - - function doListAll($command, $options, $params) - { - $savechannel = $channel = $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - if (isset($options['channel'])) { - $channel = $options['channel']; - if (!$reg->channelExists($channel)) { - return $this->raiseError("Channel \"$channel\" does not exist"); - } - - $this->config->set('default_channel', $channel); - } - - $list_options = false; - if ($this->config->get('preferred_state') == 'stable') { - $list_options = true; - } - - $chan = $reg->getChannel($channel); - if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { - return $e; - } - - if ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) { - // use faster list-all if available - $rest = &$this->config->getREST('1.1', array()); - $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName()); - } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { - $rest = &$this->config->getREST('1.0', array()); - $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName()); - } - - if (PEAR::isError($available)) { - $this->config->set('default_channel', $savechannel); - return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")'); - } - - $data = array( - 'caption' => 'All packages [Channel ' . $channel . ']:', - 'border' => true, - 'headline' => array('Package', 'Latest', 'Local'), - 'channel' => $channel, - ); - - if (isset($options['channelinfo'])) { - // add full channelinfo - $data['caption'] = 'Channel ' . $channel . ' All packages:'; - $data['headline'] = array('Channel', 'Package', 'Latest', 'Local', - 'Description', 'Dependencies'); - } - $local_pkgs = $reg->listPackages($channel); - - foreach ($available as $name => $info) { - $installed = $reg->packageInfo($name, null, $channel); - if (is_array($installed['version'])) { - $installed['version'] = $installed['version']['release']; - } - $desc = $info['summary']; - if (isset($params[$name])) { - $desc .= "\n\n".$info['description']; - } - if (isset($options['mode'])) - { - if ($options['mode'] == 'installed' && !isset($installed['version'])) { - continue; - } - if ($options['mode'] == 'notinstalled' && isset($installed['version'])) { - continue; - } - if ($options['mode'] == 'upgrades' - && (!isset($installed['version']) || version_compare($installed['version'], - $info['stable'], '>='))) { - continue; - } - } - $pos = array_search(strtolower($name), $local_pkgs); - if ($pos !== false) { - unset($local_pkgs[$pos]); - } - - if (isset($info['stable']) && !$info['stable']) { - $info['stable'] = null; - } - - if (isset($options['channelinfo'])) { - // add full channelinfo - if ($info['stable'] === $info['unstable']) { - $state = $info['state']; - } else { - $state = 'stable'; - } - $latest = $info['stable'].' ('.$state.')'; - $local = ''; - if (isset($installed['version'])) { - $inst_state = $reg->packageInfo($name, 'release_state', $channel); - $local = $installed['version'].' ('.$inst_state.')'; - } - - $packageinfo = array( - $channel, - $name, - $latest, - $local, - isset($desc) ? $desc : null, - isset($info['deps']) ? $info['deps'] : null, - ); - } else { - $packageinfo = array( - $reg->channelAlias($channel) . '/' . $name, - isset($info['stable']) ? $info['stable'] : null, - isset($installed['version']) ? $installed['version'] : null, - isset($desc) ? $desc : null, - isset($info['deps']) ? $info['deps'] : null, - ); - } - $data['data'][$info['category']][] = $packageinfo; - } - - if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) { - $this->config->set('default_channel', $savechannel); - $this->ui->outputData($data, $command); - return true; - } - - foreach ($local_pkgs as $name) { - $info = &$reg->getPackage($name, $channel); - $data['data']['Local'][] = array( - $reg->channelAlias($channel) . '/' . $info->getPackage(), - '', - $info->getVersion(), - $info->getSummary(), - $info->getDeps() - ); - } - - $this->config->set('default_channel', $savechannel); - $this->ui->outputData($data, $command); - return true; - } - - function doSearch($command, $options, $params) - { - if ((!isset($params[0]) || empty($params[0])) - && (!isset($params[1]) || empty($params[1]))) - { - return $this->raiseError('no valid search string supplied'); - } - - $channelinfo = isset($options['channelinfo']); - $reg = &$this->config->getRegistry(); - if (isset($options['allchannels'])) { - // search all channels - unset($options['allchannels']); - $channels = $reg->getChannels(); - $errors = array(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - foreach ($channels as $channel) { - if ($channel->getName() != '__uri') { - $options['channel'] = $channel->getName(); - $ret = $this->doSearch($command, $options, $params); - if (PEAR::isError($ret)) { - $errors[] = $ret; - } - } - } - - PEAR::staticPopErrorHandling(); - if (count($errors) !== 0) { - // for now, only give first error - return PEAR::raiseError($errors[0]); - } - - return true; - } - - $savechannel = $channel = $this->config->get('default_channel'); - $package = strtolower($params[0]); - $summary = isset($params[1]) ? $params[1] : false; - if (isset($options['channel'])) { - $reg = &$this->config->getRegistry(); - $channel = $options['channel']; - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); - } - - $this->config->set('default_channel', $channel); - } - - $chan = $reg->getChannel($channel); - if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { - return $e; - } - - if ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { - $rest = &$this->config->getREST('1.0', array()); - $available = $rest->listAll($base, false, false, $package, $summary, $chan->getName()); - } - - if (PEAR::isError($available)) { - $this->config->set('default_channel', $savechannel); - return $this->raiseError($available); - } - - if (!$available && !$channelinfo) { - // clean exit when not found, no error ! - $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.'; - $this->ui->outputData($data); - $this->config->set('default_channel', $channel); - return true; - } - - if ($channelinfo) { - $data = array( - 'caption' => 'Matched packages, channel ' . $channel . ':', - 'border' => true, - 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'), - 'channel' => $channel - ); - } else { - $data = array( - 'caption' => 'Matched packages, channel ' . $channel . ':', - 'border' => true, - 'headline' => array('Package', 'Stable/(Latest)', 'Local'), - 'channel' => $channel - ); - } - - if (!$available && $channelinfo) { - unset($data['headline']); - $data['data'] = 'No packages found that match pattern "' . $package . '".'; - $available = array(); - } - - foreach ($available as $name => $info) { - $installed = $reg->packageInfo($name, null, $channel); - $desc = $info['summary']; - if (isset($params[$name])) - $desc .= "\n\n".$info['description']; - - if (!isset($info['stable']) || !$info['stable']) { - $version_remote = 'none'; - } else { - if ($info['unstable']) { - $version_remote = $info['unstable']; - } else { - $version_remote = $info['stable']; - } - $version_remote .= ' ('.$info['state'].')'; - } - $version = is_array($installed['version']) ? $installed['version']['release'] : - $installed['version']; - if ($channelinfo) { - $packageinfo = array( - $channel, - $name, - $version_remote, - $version, - $desc, - ); - } else { - $packageinfo = array( - $name, - $version_remote, - $version, - $desc, - ); - } - $data['data'][$info['category']][] = $packageinfo; - } - - $this->ui->outputData($data, $command); - $this->config->set('default_channel', $channel); - return true; - } - - function &getDownloader($options) - { - if (!class_exists('PEAR_Downloader')) { - require_once 'PEAR/Downloader.php'; - } - $a = &new PEAR_Downloader($this->ui, $options, $this->config); - return $a; - } - - function doDownload($command, $options, $params) - { - // make certain that dependencies are ignored - $options['downloadonly'] = 1; - - // eliminate error messages for preferred_state-related errors - /* TODO: Should be an option, but until now download does respect - prefered state */ - /* $options['ignorepreferred_state'] = 1; */ - // eliminate error messages for preferred_state-related errors - - $downloader = &$this->getDownloader($options); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $e = $downloader->setDownloadDir(getcwd()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($e)) { - return $this->raiseError('Current directory is not writeable, cannot download'); - } - - $errors = array(); - $downloaded = array(); - $err = $downloader->download($params); - if (PEAR::isError($err)) { - return $err; - } - - $errors = $downloader->getErrorMsgs(); - if (count($errors)) { - foreach ($errors as $error) { - if ($error !== null) { - $this->ui->outputData($error); - } - } - - return $this->raiseError("$command failed"); - } - - $downloaded = $downloader->getDownloadedPackages(); - foreach ($downloaded as $pkg) { - $this->ui->outputData("File $pkg[file] downloaded", $command); - } - - return true; - } - - function downloadCallback($msg, $params = null) - { - if ($msg == 'done') { - $this->bytes_downloaded = $params; - } - } - - function doListUpgrades($command, $options, $params) - { - require_once 'PEAR/Common.php'; - if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) { - return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"'); - } - - $savechannel = $channel = $this->config->get('default_channel'); - $reg = &$this->config->getRegistry(); - foreach ($reg->listChannels() as $channel) { - $inst = array_flip($reg->listPackages($channel)); - if (!count($inst)) { - continue; - } - - if ($channel == '__uri') { - continue; - } - - $this->config->set('default_channel', $channel); - $state = empty($params[0]) ? $this->config->get('preferred_state') : $params[0]; - - $caption = $channel . ' Available Upgrades'; - $chan = $reg->getChannel($channel); - if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) { - return $e; - } - - $latest = array(); - $base2 = false; - $preferred_mirror = $this->config->get('preferred_mirror'); - if ($chan->supportsREST($preferred_mirror) && - ( - //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || - ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - - ) { - if ($base2) { - $rest = &$this->config->getREST('1.4', array()); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', array()); - } - - if (empty($state) || $state == 'any') { - $state = false; - } else { - $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')'; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg); - PEAR::staticPopErrorHandling(); - } - - if (PEAR::isError($latest)) { - $this->ui->outputData($latest->getMessage()); - continue; - } - - $caption .= ':'; - if (PEAR::isError($latest)) { - $this->config->set('default_channel', $savechannel); - return $latest; - } - - $data = array( - 'caption' => $caption, - 'border' => 1, - 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'), - 'channel' => $channel - ); - - foreach ((array)$latest as $pkg => $info) { - $package = strtolower($pkg); - if (!isset($inst[$package])) { - // skip packages we don't have installed - continue; - } - - extract($info); - $inst_version = $reg->packageInfo($package, 'version', $channel); - $inst_state = $reg->packageInfo($package, 'release_state', $channel); - if (version_compare("$version", "$inst_version", "le")) { - // installed version is up-to-date - continue; - } - - if ($filesize >= 20480) { - $filesize += 1024 - ($filesize % 1024); - $fs = sprintf("%dkB", $filesize / 1024); - } elseif ($filesize > 0) { - $filesize += 103 - ($filesize % 103); - $fs = sprintf("%.1fkB", $filesize / 1024.0); - } else { - $fs = " -"; // XXX center instead - } - - $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs); - } - - if (isset($options['channelinfo'])) { - if (empty($data['data'])) { - unset($data['headline']); - if (count($inst) == 0) { - $data['data'] = '(no packages installed)'; - } else { - $data['data'] = '(no upgrades available)'; - } - } - $this->ui->outputData($data, $command); - } else { - if (empty($data['data'])) { - $this->ui->outputData('Channel ' . $channel . ': No upgrades available'); - } else { - $this->ui->outputData($data, $command); - } - } - } - - $this->config->set('default_channel', $savechannel); - return true; - } - - function doClearCache($command, $options, $params) - { - $cache_dir = $this->config->get('cache_dir'); - $verbose = $this->config->get('verbose'); - $output = ''; - if (!file_exists($cache_dir) || !is_dir($cache_dir)) { - return $this->raiseError("$cache_dir does not exist or is not a directory"); - } - - if (!($dp = @opendir($cache_dir))) { - return $this->raiseError("opendir($cache_dir) failed: $php_errormsg"); - } - - if ($verbose >= 1) { - $output .= "reading directory $cache_dir\n"; - } - $num = 0; - while ($ent = readdir($dp)) { - if (preg_match('/rest.cache(file|id)\\z/', $ent)) { - $path = $cache_dir . DIRECTORY_SEPARATOR . $ent; - if (file_exists($path)) { - $ok = @unlink($path); - } else { - $ok = false; - $php_errormsg = ''; - } - - if ($ok) { - if ($verbose >= 2) { - $output .= "deleted $path\n"; - } - $num++; - } elseif ($verbose >= 1) { - $output .= "failed to delete $path $php_errormsg\n"; - } - } - } - - closedir($dp); - if ($verbose >= 1) { - $output .= "$num cache entries cleared\n"; - } - - $this->ui->outputData(rtrim($output), $command); - return $num; - } -}PEAR-1.9.0/PEAR/Command/Test.xml100664 764 764 3151 100664 11054 - - Run Regression Tests - doRunTests - rt - - - r - Run tests in child directories, recursively. 4 dirs deep maximum - - - i - actual string of settings to pass to php in format " -d setting=blah" - SETTINGS - - - l - Log test runs/results as they are run - - - q - Only display detail for failed tests - - - s - Display simple output for all tests - - - p - Treat parameters as installed packages from which to run tests - - - u - Search parameters for AllTests.php, and use that to run phpunit-based tests -If none is found, all .phpt tests will be tried instead. - - - t - Output run-tests.log in TAP-compliant format - - - c - CGI php executable (needed for tests with POST/GET section) - PHPCGI - - - x - Generate a code coverage report (requires Xdebug 2.0.0+) - - - [testfile|dir ...] -Run regression tests with PHP's regression testing script (run-tests.php). - -PEAR-1.9.0/PEAR/Command/Test.php100664 764 764 27267 100664 11101 - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Test.php 279072 2009-04-20 19:57:41Z cellog $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for login/logout - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ - -class PEAR_Command_Test extends PEAR_Command_Common -{ - var $commands = array( - 'run-tests' => array( - 'summary' => 'Run Regression Tests', - 'function' => 'doRunTests', - 'shortcut' => 'rt', - 'options' => array( - 'recur' => array( - 'shortopt' => 'r', - 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum', - ), - 'ini' => array( - 'shortopt' => 'i', - 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"', - 'arg' => 'SETTINGS' - ), - 'realtimelog' => array( - 'shortopt' => 'l', - 'doc' => 'Log test runs/results as they are run', - ), - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Only display detail for failed tests', - ), - 'simple' => array( - 'shortopt' => 's', - 'doc' => 'Display simple output for all tests', - ), - 'package' => array( - 'shortopt' => 'p', - 'doc' => 'Treat parameters as installed packages from which to run tests', - ), - 'phpunit' => array( - 'shortopt' => 'u', - 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests -If none is found, all .phpt tests will be tried instead.', - ), - 'tapoutput' => array( - 'shortopt' => 't', - 'doc' => 'Output run-tests.log in TAP-compliant format', - ), - 'cgi' => array( - 'shortopt' => 'c', - 'doc' => 'CGI php executable (needed for tests with POST/GET section)', - 'arg' => 'PHPCGI', - ), - 'coverage' => array( - 'shortopt' => 'x', - 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)', - ), - ), - 'doc' => '[testfile|dir ...] -Run regression tests with PHP\'s regression testing script (run-tests.php).', - ), - ); - - var $output; - - /** - * PEAR_Command_Test constructor. - * - * @access public - */ - function PEAR_Command_Test(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function doRunTests($command, $options, $params) - { - if (isset($options['phpunit']) && isset($options['tapoutput'])) { - return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time'); - } - - require_once 'PEAR/Common.php'; - require_once 'System.php'; - $log = new PEAR_Common; - $log->ui = &$this->ui; // slightly hacky, but it will work - $tests = array(); - $depth = isset($options['recur']) ? 14 : 1; - - if (!count($params)) { - $params[] = '.'; - } - - if (isset($options['package'])) { - $oldparams = $params; - $params = array(); - $reg = &$this->config->getRegistry(); - foreach ($oldparams as $param) { - $pname = $reg->parsePackageName($param, $this->config->get('default_channel')); - if (PEAR::isError($pname)) { - return $this->raiseError($pname); - } - - $package = &$reg->getPackage($pname['package'], $pname['channel']); - if (!$package) { - return PEAR::raiseError('Unknown package "' . - $reg->parsedPackageNameToString($pname) . '"'); - } - - $filelist = $package->getFilelist(); - foreach ($filelist as $name => $atts) { - if (isset($atts['role']) && $atts['role'] != 'test') { - continue; - } - - if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) { - $params[] = $atts['installed_as']; - continue; - } elseif (!preg_match('/\.phpt\\z/', $name)) { - continue; - } - $params[] = $atts['installed_as']; - } - } - } - - foreach ($params as $p) { - if (is_dir($p)) { - if (isset($options['phpunit'])) { - $dir = System::find(array($p, '-type', 'f', - '-maxdepth', $depth, - '-name', 'AllTests.php')); - if (count($dir)) { - foreach ($dir as $p) { - $p = realpath($p); - if (!count($tests) || - (count($tests) && strlen($p) < strlen($tests[0]))) { - // this is in a higher-level directory, use this one instead. - $tests = array($p); - } - } - } - continue; - } - - $args = array($p, '-type', 'f', '-name', '*.phpt'); - } else { - if (isset($options['phpunit'])) { - if (preg_match('/AllTests\.php\\z/i', $p)) { - $p = realpath($p); - if (!count($tests) || - (count($tests) && strlen($p) < strlen($tests[0]))) { - // this is in a higher-level directory, use this one instead. - $tests = array($p); - } - } - continue; - } - - if (file_exists($p) && preg_match('/\.phpt$/', $p)) { - $tests[] = $p; - continue; - } - - if (!preg_match('/\.phpt\\z/', $p)) { - $p .= '.phpt'; - } - - $args = array(dirname($p), '-type', 'f', '-name', $p); - } - - if (!isset($options['recur'])) { - $args[] = '-maxdepth'; - $args[] = 1; - } - - $dir = System::find($args); - $tests = array_merge($tests, $dir); - } - - $ini_settings = ''; - if (isset($options['ini'])) { - $ini_settings .= $options['ini']; - } - - if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) { - $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}"; - } - - if ($ini_settings) { - $this->ui->outputData('Using INI settings: "' . $ini_settings . '"'); - } - - $skipped = $passed = $failed = array(); - $tests_count = count($tests); - $this->ui->outputData('Running ' . $tests_count . ' tests', $command); - $start = time(); - if (isset($options['realtimelog']) && file_exists('run-tests.log')) { - unlink('run-tests.log'); - } - - if (isset($options['tapoutput'])) { - $tap = '1..' . $tests_count . "\n"; - } - - require_once 'PEAR/RunTest.php'; - $run = new PEAR_RunTest($log, $options); - $run->tests_count = $tests_count; - - if (isset($options['coverage']) && extension_loaded('xdebug')){ - $run->xdebug_loaded = true; - } else { - $run->xdebug_loaded = false; - } - - $j = $i = 1; - foreach ($tests as $t) { - if (isset($options['realtimelog'])) { - $fp = @fopen('run-tests.log', 'a'); - if ($fp) { - fwrite($fp, "Running test [$i / $tests_count] $t..."); - fclose($fp); - } - } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (isset($options['phpunit'])) { - $result = $run->runPHPUnit($t, $ini_settings); - } else { - $result = $run->run($t, $ini_settings, $j); - } - PEAR::staticPopErrorHandling(); - if (PEAR::isError($result)) { - $this->ui->log($result->getMessage()); - continue; - } - - if (isset($options['tapoutput'])) { - $tap .= $result[0] . ' ' . $i . $result[1] . "\n"; - continue; - } - - if (isset($options['realtimelog'])) { - $fp = @fopen('run-tests.log', 'a'); - if ($fp) { - fwrite($fp, "$result\n"); - fclose($fp); - } - } - - if ($result == 'FAILED') { - $failed[] = $t; - } - if ($result == 'PASSED') { - $passed[] = $t; - } - if ($result == 'SKIPPED') { - $skipped[] = $t; - } - - $j++; - } - - $total = date('i:s', time() - $start); - if (isset($options['tapoutput'])) { - $fp = @fopen('run-tests.log', 'w'); - if ($fp) { - fwrite($fp, $tap, strlen($tap)); - fclose($fp); - $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') . - '"', $command); - } - } else { - if (count($failed)) { - $output = "TOTAL TIME: $total\n"; - $output .= count($passed) . " PASSED TESTS\n"; - $output .= count($skipped) . " SKIPPED TESTS\n"; - $output .= count($failed) . " FAILED TESTS:\n"; - foreach ($failed as $failure) { - $output .= $failure . "\n"; - } - - $mode = isset($options['realtimelog']) ? 'a' : 'w'; - $fp = @fopen('run-tests.log', $mode); - - if ($fp) { - fwrite($fp, $output, strlen($output)); - fclose($fp); - $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command); - } - } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) { - @unlink('run-tests.log'); - } - } - $this->ui->outputData('TOTAL TIME: ' . $total); - $this->ui->outputData(count($passed) . ' PASSED TESTS', $command); - $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command); - if (count($failed)) { - $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command); - foreach ($failed as $failure) { - $this->ui->outputData($failure, $command); - } - } - - return true; - } -}PEAR-1.9.0/PEAR/Downloader/Package.php100664 764 764 226171 100664 12250 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Package.php 287560 2009-08-21 22:36:18Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Error code when parameter initialization fails because no releases - * exist within preferred_state, but releases do exist - */ -define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); -/** - * Error code when parameter initialization fails because no releases - * exist that will work with the existing PHP version - */ -define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); - -/** - * Coordinates download parameters and manages their dependencies - * prior to downloading them. - * - * Input can come from three sources: - * - * - local files (archives or package.xml) - * - remote files (downloadable urls) - * - abstract package names - * - * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires - * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the - * format returned of dependencies is slightly different from that used in package.xml. - * - * This class hides the differences between these elements, and makes automatic - * dependency resolution a piece of cake. It also manages conflicts when - * two classes depend on incompatible dependencies, or differing versions of the same - * package dependency. In addition, download will not be attempted if the php version is - * not supported, PEAR installer version is not supported, or non-PECL extensions are not - * installed. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Downloader_Package -{ - /** - * @var PEAR_Downloader - */ - var $_downloader; - /** - * @var PEAR_Config - */ - var $_config; - /** - * @var PEAR_Registry - */ - var $_registry; - /** - * Used to implement packagingroot properly - * @var PEAR_Registry - */ - var $_installRegistry; - /** - * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 - */ - var $_packagefile; - /** - * @var array - */ - var $_parsedname; - /** - * @var array - */ - var $_downloadURL; - /** - * @var array - */ - var $_downloadDeps = array(); - /** - * @var boolean - */ - var $_valid = false; - /** - * @var boolean - */ - var $_analyzed = false; - /** - * if this or a parent package was invoked with Package-state, this is set to the - * state variable. - * - * This allows temporary reassignment of preferred_state for a parent package and all of - * its dependencies. - * @var string|false - */ - var $_explicitState = false; - /** - * If this package is invoked with Package#group, this variable will be true - */ - var $_explicitGroup = false; - /** - * Package type local|url - * @var string - */ - var $_type; - /** - * Contents of package.xml, if downloaded from a remote channel - * @var string|false - * @access private - */ - var $_rawpackagefile; - /** - * @var boolean - * @access private - */ - var $_validated = false; - - /** - * @param PEAR_Downloader - */ - function PEAR_Downloader_Package(&$downloader) - { - $this->_downloader = &$downloader; - $this->_config = &$this->_downloader->config; - $this->_registry = &$this->_config->getRegistry(); - $options = $downloader->getOptions(); - if (isset($options['packagingroot'])) { - $this->_config->setInstallRoot($options['packagingroot']); - $this->_installRegistry = &$this->_config->getRegistry(); - $this->_config->setInstallRoot(false); - } else { - $this->_installRegistry = &$this->_registry; - } - $this->_valid = $this->_analyzed = false; - } - - /** - * Parse the input and determine whether this is a local file, a remote uri, or an - * abstract package name. - * - * This is the heart of the PEAR_Downloader_Package(), and is used in - * {@link PEAR_Downloader::download()} - * @param string - * @return bool|PEAR_Error - */ - function initialize($param) - { - $origErr = $this->_fromFile($param); - if ($this->_valid) { - return true; - } - - $options = $this->_downloader->getOptions(); - if (isset($options['offline'])) { - if (PEAR::isError($origErr) && !isset($options['soft'])) { - foreach ($origErr->getUserInfo() as $userInfo) { - if (isset($userInfo['message'])) { - $this->_downloader->log(0, $userInfo['message']); - } - } - - $this->_downloader->log(0, $origErr->getMessage()); - } - - return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); - } - - $err = $this->_fromUrl($param); - if (PEAR::isError($err) || !$this->_valid) { - if ($this->_type == 'url') { - if (PEAR::isError($err) && !isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } - - return PEAR::raiseError("Invalid or missing remote package file"); - } - - $err = $this->_fromString($param); - if (PEAR::isError($err) || !$this->_valid) { - if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { - return false; // instruct the downloader to silently skip - } - - if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) { - if (is_array($origErr->getUserInfo())) { - foreach ($origErr->getUserInfo() as $err) { - if (is_array($err)) { - $err = $err['message']; - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, $err); - } - } - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, $origErr->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param, true); - } - - if (!isset($options['soft'])) { - $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); - } - - // Passing no message back - already logged above - return PEAR::raiseError(); - } - - if (PEAR::isError($err) && !isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param, true); - } - - if (!isset($options['soft'])) { - $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); - } - - // Passing no message back - already logged above - return PEAR::raiseError(); - } - } - - return true; - } - - /** - * Retrieve any non-local packages - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error - */ - function &download() - { - if (isset($this->_packagefile)) { - return $this->_packagefile; - } - - if (isset($this->_downloadURL['url'])) { - $this->_isvalid = false; - $info = $this->getParsedPackage(); - foreach ($info as $i => $p) { - $info[$i] = strtolower($p); - } - - $err = $this->_fromUrl($this->_downloadURL['url'], - $this->_registry->parsedPackageNameToString($this->_parsedname, true)); - $newinfo = $this->getParsedPackage(); - foreach ($newinfo as $i => $p) { - $newinfo[$i] = strtolower($p); - } - - if ($info != $newinfo) { - do { - if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') { - $info['channel'] = 'pear.php.net'; - if ($info == $newinfo) { - // skip the channel check if a pecl package says it's a PEAR package - break; - } - } - if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') { - $info['channel'] = 'pecl.php.net'; - if ($info == $newinfo) { - // skip the channel check if a pecl package says it's a PEAR package - break; - } - } - - return PEAR::raiseError('CRITICAL ERROR: We are ' . - $this->_registry->parsedPackageNameToString($info) . ', but the file ' . - 'downloaded claims to be ' . - $this->_registry->parsedPackageNameToString($this->getParsedPackage())); - } while (false); - } - - if (PEAR::isError($err) || !$this->_valid) { - return $err; - } - } - - $this->_type = 'local'; - return $this->_packagefile; - } - - function &getPackageFile() - { - return $this->_packagefile; - } - - function &getDownloader() - { - return $this->_downloader; - } - - function getType() - { - return $this->_type; - } - - /** - * Like {@link initialize()}, but operates on a dependency - */ - function fromDepURL($dep) - { - $this->_downloadURL = $dep; - if (isset($dep['uri'])) { - $options = $this->_downloader->getOptions(); - if (!extension_loaded("zlib") || isset($options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->_fromUrl($dep['uri'] . $ext); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } - - return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . - 'cannot download'); - } - } else { - $this->_parsedname = - array( - 'package' => $dep['info']->getPackage(), - 'channel' => $dep['info']->getChannel(), - 'version' => $dep['version'] - ); - if (!isset($dep['nodefault'])) { - $this->_parsedname['group'] = 'default'; // download the default dependency group - $this->_explicitGroup = false; - } - - $this->_rawpackagefile = $dep['raw']; - } - } - - function detectDependencies($params) - { - $options = $this->_downloader->getOptions(); - if (isset($options['downloadonly'])) { - return; - } - - if (isset($options['offline'])) { - $this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); - return; - } - - $pname = $this->getParsedPackage(); - if (!$pname) { - return; - } - - $deps = $this->getDeps(); - if (!$deps) { - return; - } - - if (isset($deps['required'])) { // package.xml 2.0 - return $this->_detect2($deps, $pname, $options, $params); - } - - return $this->_detect1($deps, $pname, $options, $params); - } - - function setValidated() - { - $this->_validated = true; - } - - function alreadyValidated() - { - return $this->_validated; - } - - /** - * Remove packages to be downloaded that are already installed - * @param array of PEAR_Downloader_Package objects - * @static - */ - function removeInstalled(&$params) - { - if (!isset($params[0])) { - return; - } - - $options = $params[0]->_downloader->getOptions(); - if (!isset($options['downloadonly'])) { - foreach ($params as $i => $param) { - $package = $param->getPackage(); - $channel = $param->getChannel(); - // remove self if already installed with this version - // this does not need any pecl magic - we only remove exact matches - if ($param->_installRegistry->packageExists($package, $channel)) { - $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel); - if (version_compare($packageVersion, $param->getVersion(), '==')) { - if (!isset($options['force'])) { - $info = $param->getParsedPackage(); - unset($info['version']); - unset($info['state']); - if (!isset($options['soft'])) { - $param->_downloader->log(1, 'Skipping package "' . - $param->getShortName() . - '", already installed as version ' . $packageVersion); - } - $params[$i] = false; - } - } elseif (!isset($options['force']) && !isset($options['upgrade']) && - !isset($options['soft'])) { - $info = $param->getParsedPackage(); - $param->_downloader->log(1, 'Skipping package "' . - $param->getShortName() . - '", already installed as version ' . $packageVersion); - $params[$i] = false; - } - } - } - } - - PEAR_Downloader_Package::removeDuplicates($params); - } - - function _detect2($deps, $pname, $options, $params) - { - $this->_downloadDeps = array(); - $groupnotfound = false; - foreach (array('package', 'subpackage') as $packagetype) { - // get required dependency group - if (isset($deps['required'][$packagetype])) { - if (isset($deps['required'][$packagetype][0])) { - foreach ($deps['required'][$packagetype] as $dep) { - if (isset($dep['conflicts'])) { - // skip any package that this package conflicts with - continue; - } - $ret = $this->_detect2Dep($dep, $pname, 'required', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } else { - $dep = $deps['required'][$packagetype]; - if (!isset($dep['conflicts'])) { - // skip any package that this package conflicts with - $ret = $this->_detect2Dep($dep, $pname, 'required', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } - } - - // get optional dependency group, if any - if (isset($deps['optional'][$packagetype])) { - $skipnames = array(); - if (!isset($deps['optional'][$packagetype][0])) { - $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); - } - - foreach ($deps['optional'][$packagetype] as $dep) { - $skip = false; - if (!isset($options['alldeps'])) { - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->_registry->parsedPackageNameToString($this->getParsedPackage(), - true) . '" optional dependency "' . - $this->_registry->parsedPackageNameToString(array('package' => - $dep['name'], 'channel' => 'pear.php.net'), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); - $skip = true; - unset($dep['package']); - } - - $ret = $this->_detect2Dep($dep, $pname, 'optional', $params); - if (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - - if (!$ret) { - $dep['package'] = $dep['name']; - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - } - - if (!$skip && is_array($ret)) { - $this->_downloadDeps[] = $ret; - } - } - - if (count($skipnames)) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'Did not download optional dependencies: ' . - implode(', ', $skipnames) . - ', use --alldeps to download automatically'); - } - } - } - - // get requested dependency group, if any - $groupname = $this->getGroup(); - $explicit = $this->_explicitGroup; - if (!$groupname) { - if (!$this->canDefault()) { - continue; - } - - $groupname = 'default'; // try the default dependency group - } - - if ($groupnotfound) { - continue; - } - - if (isset($deps['group'])) { - if (isset($deps['group']['attribs'])) { - if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { - $group = $deps['group']; - } elseif ($explicit) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Warning: package "' . - $this->_registry->parsedPackageNameToString($pname, true) . - '" has no dependency ' . 'group named "' . $groupname . '"'); - } - - $groupnotfound = true; - continue; - } - } else { - $found = false; - foreach ($deps['group'] as $group) { - if (strtolower($group['attribs']['name']) == strtolower($groupname)) { - $found = true; - break; - } - } - - if (!$found) { - if ($explicit) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Warning: package "' . - $this->_registry->parsedPackageNameToString($pname, true) . - '" has no dependency ' . 'group named "' . $groupname . '"'); - } - } - - $groupnotfound = true; - continue; - } - } - } - - if (isset($group) && isset($group[$packagetype])) { - if (isset($group[$packagetype][0])) { - foreach ($group[$packagetype] as $dep) { - $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . - $group['attribs']['name'] . '"', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } else { - $ret = $this->_detect2Dep($group[$packagetype], $pname, - 'dependency group "' . - $group['attribs']['name'] . '"', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } - } - } - - function _detect2Dep($dep, $pname, $group, $params) - { - if (isset($dep['conflicts'])) { - return true; - } - - $options = $this->_downloader->getOptions(); - if (isset($dep['uri'])) { - return array('uri' => $dep['uri'], 'dep' => $dep);; - } - - $testdep = $dep; - $testdep['package'] = $dep['name']; - if (PEAR_Downloader_Package::willDownload($testdep, $params)) { - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", will be installed'); - } - return false; - } - - $options = $this->_downloader->getOptions(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if ($this->_explicitState) { - $pname['state'] = $this->_explicitState; - } - - $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); - if (PEAR::isError($url)) { - PEAR::popErrorHandling(); - return $url; - } - - $dep['package'] = $dep['name']; - $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && - !isset($options['alldeps']), true); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - - return false; - } - - // check to see if a dep is already installed and is the same or newer - if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { - $oper = 'has'; - } else { - $oper = 'gt'; - } - - // do not try to move this before getDepPackageDownloadURL - // we can't determine whether upgrade is necessary until we know what - // version would be downloaded - if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']); - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '" version ' . $url['version'] . ', already installed as version ' . - $version); - } - - return false; - } - - if (isset($dep['nodefault'])) { - $ret['nodefault'] = true; - } - - return $ret; - } - - function _detect1($deps, $pname, $options, $params) - { - $this->_downloadDeps = array(); - $skipnames = array(); - foreach ($deps as $dep) { - $nodownload = false; - if (isset ($dep['type']) && $dep['type'] === 'pkg') { - $dep['channel'] = 'pear.php.net'; - $dep['package'] = $dep['name']; - switch ($dep['rel']) { - case 'not' : - continue 2; - case 'ge' : - case 'eq' : - case 'gt' : - case 'has' : - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - if (PEAR_Downloader_Package::willDownload($dep, $params)) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group - . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", will be installed'); - continue 2; - } - $fakedp = new PEAR_PackageFile_v1; - $fakedp->setPackage($dep['name']); - // skip internet check if we are not upgrading (bug #5810) - if (!isset($options['upgrade']) && $this->isInstalled( - $fakedp, $dep['rel'])) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group - . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", is already installed'); - continue 2; - } - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if ($this->_explicitState) { - $pname['state'] = $this->_explicitState; - } - - $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); - $chan = 'pear.php.net'; - if (PEAR::isError($url)) { - // check to see if this is a pecl package that has jumped - // from pear.php.net to pecl.php.net channel - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - - $newdep = PEAR_Dependency2::normalizeDep($dep); - $newdep = $newdep[0]; - $newdep['channel'] = 'pecl.php.net'; - $chan = 'pecl.php.net'; - $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); - $obj = &$this->_installRegistry->getPackage($dep['name']); - if (PEAR::isError($url)) { - PEAR::popErrorHandling(); - if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . - ': Skipping ' . $group . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", already installed as version ' . $obj->getVersion()); - } - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - continue; - } else { - if (isset($dep['optional']) && $dep['optional'] == 'yes') { - $this->_downloader->log(2, $this->getShortName() . - ': Skipping optional dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", no releases exist'); - continue; - } else { - return $url; - } - } - } - } - - PEAR::popErrorHandling(); - if (!isset($options['alldeps'])) { - if (isset($dep['optional']) && $dep['optional'] == 'yes') { - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->getShortName() . - '" optional dependency "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true); - $nodownload = true; - } - } - - if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { - if (!isset($dep['optional']) || $dep['optional'] == 'no') { - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->getShortName() . - '" required dependency "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true); - $nodownload = true; - } - } - - // check to see if a dep is already installed - // do not try to move this before getDepPackageDownloadURL - // we can't determine whether upgrade is necessary until we know what - // version would be downloaded - if (!isset($options['force']) && $this->isInstalled( - $url, $dep['rel'])) { - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - $dep['package'] = $dep['name']; - if (isset($newdep)) { - $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']); - } else { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); - } - - $dep['version'] = $url['version']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", already installed as version ' . $version); - } - - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - - continue; - } - - if ($nodownload) { - continue; - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (isset($newdep)) { - $dep = $newdep; - } - - $dep['package'] = $dep['name']; - $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, - isset($dep['optional']) && $dep['optional'] == 'yes' && - !isset($options['alldeps']), true); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - continue; - } - - $this->_downloadDeps[] = $ret; - } - } - - if (count($skipnames)) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'Did not download dependencies: ' . - implode(', ', $skipnames) . - ', use --alldeps or --onlyreqdeps to download automatically'); - } - } - } - - function setDownloadURL($pkg) - { - $this->_downloadURL = $pkg; - } - - /** - * Set the package.xml object for this downloaded package - * - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg - */ - function setPackageFile(&$pkg) - { - $this->_packagefile = &$pkg; - } - - function getShortName() - { - return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), - 'package' => $this->getPackage()), true); - } - - function getParsedPackage() - { - if (isset($this->_packagefile) || isset($this->_parsedname)) { - return array('channel' => $this->getChannel(), - 'package' => $this->getPackage(), - 'version' => $this->getVersion()); - } - - return false; - } - - function getDownloadURL() - { - return $this->_downloadURL; - } - - function canDefault() - { - if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) { - return false; - } - - return true; - } - - function getPackage() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackage(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackage(); - } - - return false; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function isSubpackage(&$pf) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isSubpackage($pf); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->isSubpackage($pf); - } - - return false; - } - - function getPackageType() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackageType(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackageType(); - } - - return false; - } - - function isBundle() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackageType() == 'bundle'; - } - - return false; - } - - function getPackageXmlVersion() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackagexmlVersion(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackagexmlVersion(); - } - - return '1.0'; - } - - function getChannel() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getChannel(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getChannel(); - } - - return false; - } - - function getURI() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getURI(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getURI(); - } - - return false; - } - - function getVersion() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getVersion(); - } elseif (isset($this->_downloadURL['version'])) { - return $this->_downloadURL['version']; - } - - return false; - } - - function isCompatible($pf) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isCompatible($pf); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->isCompatible($pf); - } - - return true; - } - - function setGroup($group) - { - $this->_parsedname['group'] = $group; - } - - function getGroup() - { - if (isset($this->_parsedname['group'])) { - return $this->_parsedname['group']; - } - - return ''; - } - - function isExtension($name) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isExtension($name); - } elseif (isset($this->_downloadURL['info'])) { - if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { - return $this->_downloadURL['info']->getProvidesExtension() == $name; - } - - return false; - } - - return false; - } - - function getDeps() - { - if (isset($this->_packagefile)) { - $ver = $this->_packagefile->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - return $this->_packagefile->getDeps(true); - } - - return $this->_packagefile->getDeps(); - } elseif (isset($this->_downloadURL['info'])) { - $ver = $this->_downloadURL['info']->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - return $this->_downloadURL['info']->getDeps(true); - } - - return $this->_downloadURL['info']->getDeps(); - } - - return array(); - } - - /** - * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency - * returned from getDepDownloadURL() - */ - function isEqual($param) - { - if (is_object($param)) { - $channel = $param->getChannel(); - $package = $param->getPackage(); - if ($param->getURI()) { - $param = array( - 'channel' => $param->getChannel(), - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - 'uri' => $param->getURI(), - ); - } else { - $param = array( - 'channel' => $param->getChannel(), - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - ); - } - } else { - if (isset($param['uri'])) { - if ($this->getChannel() != '__uri') { - return false; - } - return $param['uri'] == $this->getURI(); - } - - $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage(); - $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel(); - if (isset($param['rel'])) { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - - $newdep = PEAR_Dependency2::normalizeDep($param); - $newdep = $newdep[0]; - } elseif (isset($param['min'])) { - $newdep = $param; - } - } - - if (isset($newdep)) { - if (!isset($newdep['min'])) { - $newdep['min'] = '0'; - } - - if (!isset($newdep['max'])) { - $newdep['max'] = '100000000000000000000'; - } - - // use magic to support pecl packages suddenly jumping to the pecl channel - // we need to support both dependency possibilities - if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { - if ($package == $this->getPackage()) { - $channel = 'pecl.php.net'; - } - } - if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { - if ($package == $this->getPackage()) { - $channel = 'pear.php.net'; - } - } - - return (strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel() && - version_compare($newdep['min'], $this->getVersion(), '<=') && - version_compare($newdep['max'], $this->getVersion(), '>=')); - } - - // use magic to support pecl packages suddenly jumping to the pecl channel - if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { - if (strtolower($package) == strtolower($this->getPackage())) { - $channel = 'pear.php.net'; - } - } - - if (isset($param['version'])) { - return (strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel() && - $param['version'] == $this->getVersion()); - } - - return strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel(); - } - - function isInstalled($dep, $oper = '==') - { - if (!$dep) { - return false; - } - - if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { - return false; - } - - if (is_object($dep)) { - $package = $dep->getPackage(); - $channel = $dep->getChannel(); - if ($dep->getURI()) { - $dep = array( - 'uri' => $dep->getURI(), - 'version' => $dep->getVersion(), - ); - } else { - $dep = array( - 'version' => $dep->getVersion(), - ); - } - } else { - if (isset($dep['uri'])) { - $channel = '__uri'; - $package = $dep['dep']['name']; - } else { - $channel = $dep['info']->getChannel(); - $package = $dep['info']->getPackage(); - } - } - - $options = $this->_downloader->getOptions(); - $test = $this->_installRegistry->packageExists($package, $channel); - if (!$test && $channel == 'pecl.php.net') { - // do magic to allow upgrading from old pecl packages to new ones - $test = $this->_installRegistry->packageExists($package, 'pear.php.net'); - $channel = 'pear.php.net'; - } - - if ($test) { - if (isset($dep['uri'])) { - if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { - return true; - } - } - - if (isset($options['upgrade'])) { - $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel); - if (version_compare($packageVersion, $dep['version'], '>=')) { - return true; - } - - return false; - } - - return true; - } - - return false; - } - - /** - * Detect duplicate package names with differing versions - * - * If a user requests to install Date 1.4.6 and Date 1.4.7, - * for instance, this is a logic error. This method - * detects this situation. - * - * @param array $params array of PEAR_Downloader_Package objects - * @param array $errorparams empty array - * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts - */ - function detectStupidDuplicates($params, &$errorparams) - { - $existing = array(); - foreach ($params as $i => $param) { - $package = $param->getPackage(); - $channel = $param->getChannel(); - $group = $param->getGroup(); - if (!isset($existing[$channel . '/' . $package])) { - $existing[$channel . '/' . $package] = array(); - } - - if (!isset($existing[$channel . '/' . $package][$group])) { - $existing[$channel . '/' . $package][$group] = array(); - } - - $existing[$channel . '/' . $package][$group][] = $i; - } - - $indices = array(); - foreach ($existing as $package => $groups) { - foreach ($groups as $group => $dupes) { - if (count($dupes) > 1) { - $indices = $indices + $dupes; - } - } - } - - $indices = array_unique($indices); - foreach ($indices as $index) { - $errorparams[] = $params[$index]; - } - - return count($errorparams); - } - - /** - * @param array - * @param bool ignore install groups - for final removal of dupe packages - * @static - */ - function removeDuplicates(&$params, $ignoreGroups = false) - { - $pnames = array(); - foreach ($params as $i => $param) { - if (!$param) { - continue; - } - - if ($param->getPackage()) { - $group = $ignoreGroups ? '' : $param->getGroup(); - $pnames[$i] = $param->getChannel() . '/' . - $param->getPackage() . '-' . $param->getVersion() . '#' . $group; - } - } - - $pnames = array_unique($pnames); - $unset = array_diff(array_keys($params), array_keys($pnames)); - $testp = array_flip($pnames); - foreach ($params as $i => $param) { - if (!$param) { - $unset[] = $i; - continue; - } - - if (!is_a($param, 'PEAR_Downloader_Package')) { - $unset[] = $i; - continue; - } - - $group = $ignoreGroups ? '' : $param->getGroup(); - if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . - $param->getVersion() . '#' . $group])) { - $unset[] = $i; - } - } - - foreach ($unset as $i) { - unset($params[$i]); - } - - $ret = array(); - foreach ($params as $i => $param) { - $ret[] = &$params[$i]; - } - - $params = array(); - foreach ($ret as $i => $param) { - $params[] = &$ret[$i]; - } - } - - function explicitState() - { - return $this->_explicitState; - } - - function setExplicitState($s) - { - $this->_explicitState = $s; - } - - /** - * @static - */ - function mergeDependencies(&$params) - { - $bundles = $newparams = array(); - foreach ($params as $i => $param) { - if (!$param->isBundle()) { - continue; - } - - $bundles[] = $i; - $pf = &$param->getPackageFile(); - $newdeps = array(); - $contents = $pf->getBundledPackages(); - if (!is_array($contents)) { - $contents = array($contents); - } - - foreach ($contents as $file) { - $filecontents = $pf->getFileContents($file); - $dl = &$param->getDownloader(); - $options = $dl->getOptions(); - if (PEAR::isError($dir = $dl->getDownloadDir())) { - return $dir; - } - - $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); - if (!$fp) { - continue; - } - - fwrite($fp, $filecontents, strlen($filecontents)); - fclose($fp); - if ($s = $params[$i]->explicitState()) { - $obj->setExplicitState($s); - } - - $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($dir = $dl->getDownloadDir())) { - PEAR::popErrorHandling(); - return $dir; - } - - $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file); - PEAR::popErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $dl->log(0, $e->getMessage()); - } - continue; - } - - $j = &$obj; - if (!PEAR_Downloader_Package::willDownload($j, - array_merge($params, $newparams)) && !$param->isInstalled($j)) { - $newparams[] = &$j; - } - } - } - - foreach ($bundles as $i) { - unset($params[$i]); // remove bundles - only their contents matter for installation - } - - PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices - if (count($newparams)) { // add in bundled packages for install - foreach ($newparams as $i => $unused) { - $params[] = &$newparams[$i]; - } - $newparams = array(); - } - - foreach ($params as $i => $param) { - $newdeps = array(); - foreach ($param->_downloadDeps as $dep) { - $merge = array_merge($params, $newparams); - if (!PEAR_Downloader_Package::willDownload($dep, $merge) - && !$param->isInstalled($dep) - ) { - $newdeps[] = $dep; - } else { - //var_dump($dep); - // detect versioning conflicts here - } - } - - // convert the dependencies into PEAR_Downloader_Package objects for the next time around - $params[$i]->_downloadDeps = array(); - foreach ($newdeps as $dep) { - $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); - if ($s = $params[$i]->explicitState()) { - $obj->setExplicitState($s); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $e = $obj->fromDepURL($dep); - PEAR::popErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $obj->_downloader->log(0, $e->getMessage()); - } - continue; - } - - $e = $obj->detectDependencies($params); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $obj->_downloader->log(0, $e->getMessage()); - } - } - - $j = &$obj; - $newparams[] = &$j; - } - } - - if (count($newparams)) { - foreach ($newparams as $i => $unused) { - $params[] = &$newparams[$i]; - } - return true; - } - - return false; - } - - - /** - * @static - */ - function willDownload($param, $params) - { - if (!is_array($params)) { - return false; - } - - foreach ($params as $obj) { - if ($obj->isEqual($param)) { - return true; - } - } - - return false; - } - - /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string - */ - function &getPackagefileObject(&$c, $d, $t = false) - { - $a = &new PEAR_PackageFile($c, $d, $t); - return $a; - } - - - /** - * This will retrieve from a local file if possible, and parse out - * a group name as well. The original parameter will be modified to reflect this. - * @param string|array can be a parsed package name as well - * @access private - */ - function _fromFile(&$param) - { - $saveparam = $param; - if (is_string($param)) { - if (!@file_exists($param)) { - $test = explode('#', $param); - $group = array_pop($test); - if (@file_exists(implode('#', $test))) { - $this->setGroup($group); - $param = implode('#', $test); - $this->_explicitGroup = true; - } - } - - if (@is_file($param)) { - $this->_type = 'local'; - $options = $this->_downloader->getOptions(); - if (isset($options['downloadonly'])) { - $pkg = &$this->getPackagefileObject($this->_config, - $this->_downloader->_debug); - } else { - if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { - return $dir; - } - $pkg = &$this->getPackagefileObject($this->_config, - $this->_downloader->_debug, $dir); - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); - PEAR::popErrorHandling(); - if (PEAR::isError($pf)) { - $this->_valid = false; - $param = $saveparam; - return $pf; - } - $this->_packagefile = &$pf; - if (!$this->getGroup()) { - $this->setGroup('default'); // install the default dependency group - } - return $this->_valid = true; - } - } - $param = $saveparam; - return $this->_valid = false; - } - - function _fromUrl($param, $saveparam = '') - { - if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) { - $options = $this->_downloader->getOptions(); - $this->_type = 'url'; - $callback = $this->_downloader->ui ? - array(&$this->_downloader, '_downloadCallback') : null; - $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { - $this->_downloader->popErrorHandling(); - return $dir; - } - - $this->_downloader->log(3, 'Downloading "' . $param . '"'); - $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, - $dir, $callback, null, false, $this->getChannel()); - $this->_downloader->popErrorHandling(); - if (PEAR::isError($file)) { - if (!empty($saveparam)) { - $saveparam = ", cannot download \"$saveparam\""; - } - $err = PEAR::raiseError('Could not download from "' . $param . - '"' . $saveparam . ' (' . $file->getMessage() . ')'); - return $err; - } - - if ($this->_rawpackagefile) { - require_once 'Archive/Tar.php'; - $tar = &new Archive_Tar($file); - $packagexml = $tar->extractInString('package2.xml'); - if (!$packagexml) { - $packagexml = $tar->extractInString('package.xml'); - } - - if (str_replace(array("\n", "\r"), array('',''), $packagexml) != - str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { - if ($this->getChannel() != 'pear.php.net') { - return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . - 'not match value returned from xml-rpc'); - } - - // be more lax for the existing PEAR packages that have not-ok - // characters in their package.xml - $this->_downloader->log(0, 'CRITICAL WARNING: The "' . - $this->getPackage() . '" package has invalid characters in its ' . - 'package.xml. The next version of PEAR may not be able to install ' . - 'this package for security reasons. Please open a bug report at ' . - 'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); - } - } - - // whew, download worked! - if (isset($options['downloadonly'])) { - $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); - } else { - $dir = $this->_downloader->getDownloadDir(); - if (PEAR::isError($dir)) { - return $dir; - } - $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug, $dir); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); - PEAR::popErrorHandling(); - if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $err) { - if (is_array($err)) { - $err = $err['message']; - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, "Validation Error: $err"); - } - } - } - - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pf->getMessage()); - } - - ///FIXME need to pass back some error code that we can use to match with to cancel all further operations - /// At least stop all deps of this package from being installed - $out = $saveparam ? $saveparam : $param; - $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive'); - $this->_valid = false; - return $err; - } - - $this->_packagefile = &$pf; - $this->setGroup('default'); // install the default dependency group - return $this->_valid = true; - } - - return $this->_valid = false; - } - - /** - * - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',]) - * or a string of format [channame/]pname[-version|-state] - */ - function _fromString($param) - { - $options = $this->_downloader->getOptions(); - $channel = $this->_config->get('default_channel'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pname = $this->_registry->parsePackageName($param, $channel); - PEAR::popErrorHandling(); - if (PEAR::isError($pname)) { - if ($pname->getCode() == 'invalid') { - $this->_valid = false; - return false; - } - - if ($pname->getCode() == 'channel') { - $parsed = $pname->getUserInfo(); - if ($this->_downloader->discover($parsed['channel'])) { - if ($this->_config->get('auto_discover')) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pname = $this->_registry->parsePackageName($param, $channel); - PEAR::popErrorHandling(); - } else { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Channel "' . $parsed['channel'] . - '" is not initialized, use ' . - '"pear channel-discover ' . $parsed['channel'] . '" to initialize' . - 'or pear config-set auto_discover 1'); - } - } - } - - if (PEAR::isError($pname)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pname->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param); - } - - $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); - $this->_valid = false; - return $err; - } - } else { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pname->getMessage()); - } - - $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); - $this->_valid = false; - return $err; - } - } - - if (!isset($this->_type)) { - $this->_type = 'rest'; - } - - $this->_parsedname = $pname; - $this->_explicitState = isset($pname['state']) ? $pname['state'] : false; - $this->_explicitGroup = isset($pname['group']) ? true : false; - - $info = $this->_downloader->_getPackageDownloadUrl($pname); - if (PEAR::isError($info)) { - if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { - // try pecl - $pname['channel'] = 'pecl.php.net'; - if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { - if (!PEAR::isError($test)) { - $info = PEAR::raiseError($info->getMessage() . ' - package ' . - $this->_registry->parsedPackageNameToString($pname, true) . - ' can be installed with "pecl install ' . $pname['package'] . - '"'); - } else { - $pname['channel'] = 'pear.php.net'; - } - } else { - $pname['channel'] = 'pear.php.net'; - } - } - - return $info; - } - - $this->_rawpackagefile = $info['raw']; - $ret = $this->_analyzeDownloadURL($info, $param, $pname); - if (PEAR::isError($ret)) { - return $ret; - } - - if ($ret) { - $this->_downloadURL = $ret; - return $this->_valid = (bool) $ret; - } - } - - /** - * @param array output of package.getDownloadURL - * @param string|array|object information for detecting packages to be downloaded, and - * for errors - * @param array name information of the package - * @param array|null packages to be downloaded - * @param bool is this an optional dependency? - * @param bool is this any kind of dependency? - * @access private - */ - function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, - $isdependency = false) - { - if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { - return false; - } - - if ($info === false) { - $saveparam = !is_string($param) ? ", cannot download \"$param\"" : ''; - - // no releases exist - return PEAR::raiseError('No releases for package "' . - $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); - } - - if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { - $err = false; - if ($pname['channel'] == 'pecl.php.net') { - if ($info['info']->getChannel() != 'pear.php.net') { - $err = true; - } - } elseif ($info['info']->getChannel() == 'pecl.php.net') { - if ($pname['channel'] != 'pear.php.net') { - $err = true; - } - } else { - $err = true; - } - - if ($err) { - return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . - '" retrieved another channel\'s name for download! ("' . - $info['info']->getChannel() . '")'); - } - } - - $preferred_state = $this->_config->get('preferred_state'); - if (!isset($info['url'])) { - $package_version = $this->_registry->packageInfo($info['info']->getPackage(), - 'version', $info['info']->getChannel()); - if ($this->isInstalled($info)) { - if ($isdependency && version_compare($info['version'], $package_version, '<=')) { - // ignore bogus errors of "failed to download dependency" - // if it is already installed and the one that would be - // downloaded is older or the same version (Bug #7219) - return false; - } - } - - if ($info['version'] === $package_version) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' . - ' (' . $package_version . ') is the same as the locally installed one.'); - } - - return false; - } - - if (version_compare($info['version'], $package_version, '<=')) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . - ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); - } - - return false; - } - - $instead = ', will instead download version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '"'; - // releases exist, but we failed to get any - if (isset($this->_downloader->_options['force'])) { - if (isset($pname['version'])) { - $vs = ', version "' . $pname['version'] . '"'; - } elseif (isset($pname['state'])) { - $vs = ', stability "' . $pname['state'] . '"'; - } elseif ($param == 'dependency') { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - - if (!in_array($info['info']->getState(), - PEAR_Common::betterStates($preferred_state, true))) { - if ($optional) { - // don't spit out confusing error message - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = ' within preferred state "' . $preferred_state . - '"'; - } else { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - - if ($optional) { - // don't spit out confusing error message - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = PEAR_Dependency2::_getExtraString($pname); - $instead = ''; - } - } else { - $vs = ' within preferred state "' . $preferred_state . '"'; - } - - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . $vs . $instead); - } - - // download the latest release - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } else { - if (isset($info['php']) && $info['php']) { - $err = PEAR::raiseError('Failed to download ' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], - 'package' => $pname['package']), - true) . - ', latest release is version ' . $info['php']['v'] . - ', but it requires PHP version "' . - $info['php']['m'] . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['php']['v'])) . '" to install', - PEAR_DOWNLOADER_PACKAGE_PHPVERSION); - return $err; - } - - // construct helpful error message - if (isset($pname['version'])) { - $vs = ', version "' . $pname['version'] . '"'; - } elseif (isset($pname['state'])) { - $vs = ', stability "' . $pname['state'] . '"'; - } elseif ($param == 'dependency') { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - - if (!in_array($info['info']->getState(), - PEAR_Common::betterStates($preferred_state, true))) { - if ($optional) { - // don't spit out confusing error message, and don't die on - // optional dep failure! - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = ' within preferred state "' . $preferred_state . '"'; - } else { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - - if ($optional) { - // don't spit out confusing error message, and don't die on - // optional dep failure! - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = PEAR_Dependency2::_getExtraString($pname); - } - } else { - $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"'; - } - - $options = $this->_downloader->getOptions(); - // this is only set by the "download-all" command - if (isset($options['ignorepreferred_state'])) { - $err = PEAR::raiseError( - 'Failed to download ' . $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package']), - true) - . $vs . - ', latest release is version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['version'])) . '" to install', - PEAR_DOWNLOADER_PACKAGE_STATE); - return $err; - } - - // Checks if the user has a package installed already and checks the release against - // the state against the installed package, this allows upgrades for packages - // with lower stability than the preferred_state - $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']); - if (!$this->isInstalled($info) - || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true)) - ) { - $err = PEAR::raiseError( - 'Failed to download ' . $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package']), - true) - . $vs . - ', latest release is version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['version'])) . '" to install'); - return $err; - } - } - } - - if (isset($info['deprecated']) && $info['deprecated']) { - $this->_downloader->log(0, - 'WARNING: "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $info['info']->getChannel(), - 'package' => $info['info']->getPackage()), true) . - '" is deprecated in favor of "' . - $this->_registry->parsedPackageNameToString($info['deprecated'], true) . - '"'); - } - - return $info; - } -}PEAR-1.9.0/PEAR/Frontend/CLI.php100664 764 764 60642 100664 10764 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: CLI.php 278236 2009-04-04 00:09:14Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ -/** - * base class - */ -require_once 'PEAR/Frontend.php'; - -/** - * Command-line Frontend for the PEAR Installer - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Frontend_CLI extends PEAR_Frontend -{ - /** - * What type of user interface this frontend is for. - * @var string - * @access public - */ - var $type = 'CLI'; - var $lp = ''; // line prefix - - var $params = array(); - var $term = array( - 'bold' => '', - 'normal' => '', - ); - - function PEAR_Frontend_CLI() - { - parent::PEAR(); - $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 - if (function_exists('posix_isatty') && !posix_isatty(1)) { - // output is being redirected to a file or through a pipe - } elseif ($term) { - if (preg_match('/^(xterm|vt220|linux)/', $term)) { - $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); - $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109); - } elseif (preg_match('/^vt100/', $term)) { - $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); - $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); - } - } elseif (OS_WINDOWS) { - // XXX add ANSI codes here - } - } - - /** - * @param object PEAR_Error object - */ - function displayError($e) - { - return $this->_displayLine($e->getMessage()); - } - - /** - * @param object PEAR_Error object - */ - function displayFatalError($eobj) - { - $this->displayError($eobj); - if (class_exists('PEAR_Config')) { - $config = &PEAR_Config::singleton(); - if ($config->get('verbose') > 5) { - if (function_exists('debug_print_backtrace')) { - debug_print_backtrace(); - exit(1); - } - - $raised = false; - foreach (debug_backtrace() as $i => $frame) { - if (!$raised) { - if (isset($frame['class']) - && strtolower($frame['class']) == 'pear' - && strtolower($frame['function']) == 'raiseerror' - ) { - $raised = true; - } else { - continue; - } - } - - $frame['class'] = !isset($frame['class']) ? '' : $frame['class']; - $frame['type'] = !isset($frame['type']) ? '' : $frame['type']; - $frame['function'] = !isset($frame['function']) ? '' : $frame['function']; - $frame['line'] = !isset($frame['line']) ? '' : $frame['line']; - $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); - } - } - } - - exit(1); - } - - /** - * Instruct the runInstallScript method to skip a paramgroup that matches the - * id value passed in. - * - * This method is useful for dynamically configuring which sections of a post-install script - * will be run based on the user's setup, which is very useful for making flexible - * post-install scripts without losing the cross-Frontend ability to retrieve user input - * @param string - */ - function skipParamgroup($id) - { - $this->_skipSections[$id] = true; - } - - function runPostinstallScripts(&$scripts) - { - foreach ($scripts as $i => $script) { - $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); - } - } - - /** - * @param array $xml contents of postinstallscript tag - * @param object $script post-installation script - * @param string install|upgrade - */ - function runInstallScript($xml, &$script) - { - $this->_skipSections = array(); - if (!is_array($xml) || !isset($xml['paramgroup'])) { - $script->run(array(), '_default'); - return; - } - - $completedPhases = array(); - if (!isset($xml['paramgroup'][0])) { - $xml['paramgroup'] = array($xml['paramgroup']); - } - - foreach ($xml['paramgroup'] as $group) { - if (isset($this->_skipSections[$group['id']])) { - // the post-install script chose to skip this section dynamically - continue; - } - - if (isset($group['name'])) { - $paramname = explode('::', $group['name']); - if ($lastgroup['id'] != $paramname[0]) { - continue; - } - - $group['name'] = $paramname[1]; - if (!isset($answers)) { - return; - } - - if (isset($answers[$group['name']])) { - switch ($group['conditiontype']) { - case '=' : - if ($answers[$group['name']] != $group['value']) { - continue 2; - } - break; - case '!=' : - if ($answers[$group['name']] == $group['value']) { - continue 2; - } - break; - case 'preg_match' : - if (!@preg_match('/' . $group['value'] . '/', - $answers[$group['name']])) { - continue 2; - } - break; - default : - return; - } - } - } - - $lastgroup = $group; - if (isset($group['instructions'])) { - $this->_display($group['instructions']); - } - - if (!isset($group['param'][0])) { - $group['param'] = array($group['param']); - } - - if (isset($group['param'])) { - if (method_exists($script, 'postProcessPrompts')) { - $prompts = $script->postProcessPrompts($group['param'], $group['id']); - if (!is_array($prompts) || count($prompts) != count($group['param'])) { - $this->outputData('postinstall', 'Error: post-install script did not ' . - 'return proper post-processed prompts'); - $prompts = $group['param']; - } else { - foreach ($prompts as $i => $var) { - if (!is_array($var) || !isset($var['prompt']) || - !isset($var['name']) || - ($var['name'] != $group['param'][$i]['name']) || - ($var['type'] != $group['param'][$i]['type']) - ) { - $this->outputData('postinstall', 'Error: post-install script ' . - 'modified the variables or prompts, severe security risk. ' . - 'Will instead use the defaults from the package.xml'); - $prompts = $group['param']; - } - } - } - - $answers = $this->confirmDialog($prompts); - } else { - $answers = $this->confirmDialog($group['param']); - } - } - - if ((isset($answers) && $answers) || !isset($group['param'])) { - if (!isset($answers)) { - $answers = array(); - } - - array_unshift($completedPhases, $group['id']); - if (!$script->run($answers, $group['id'])) { - $script->run($completedPhases, '_undoOnError'); - return; - } - } else { - $script->run($completedPhases, '_undoOnError'); - return; - } - } - } - - /** - * Ask for user input, confirm the answers and continue until the user is satisfied - * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => - * 'text to display', 'type' => 'string'[, default => 'default value']) - * @return array - */ - function confirmDialog($params) - { - $answers = $prompts = $types = array(); - foreach ($params as $param) { - $prompts[$param['name']] = $param['prompt']; - $types[$param['name']] = $param['type']; - $answers[$param['name']] = isset($param['default']) ? $param['default'] : ''; - } - - $tried = false; - do { - if ($tried) { - $i = 1; - foreach ($answers as $var => $value) { - if (!strlen($value)) { - echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); - } - $i++; - } - } - - $answers = $this->userDialog('', $prompts, $types, $answers); - $tried = true; - } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); - - return $answers; - } - - function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20) - { - if (!is_array($prompts)) { - return array(); - } - - $testprompts = array_keys($prompts); - $result = $defaults; - - reset($prompts); - if (count($prompts) === 1) { - foreach ($prompts as $key => $prompt) { - $type = $types[$key]; - $default = @$defaults[$key]; - print "$prompt "; - if ($default) { - print "[$default] "; - } - print ": "; - - $line = fgets(STDIN, 2048); - $result[$key] = ($default && trim($line) == '') ? $default : trim($line); - } - - return $result; - } - - $first_run = true; - while (true) { - $descLength = max(array_map('strlen', $prompts)); - $descFormat = "%-{$descLength}s"; - $last = count($prompts); - - $i = 0; - foreach ($prompts as $n => $var) { - $res = isset($result[$n]) ? $result[$n] : null; - printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res); - } - print "\n1-$last, 'all', 'abort', or Enter to continue: "; - - $tmp = trim(fgets(STDIN, 1024)); - if (empty($tmp)) { - break; - } - - if ($tmp == 'abort') { - return false; - } - - if (isset($testprompts[(int)$tmp - 1])) { - $var = $testprompts[(int)$tmp - 1]; - $desc = $prompts[$var]; - $current = @$result[$var]; - print "$desc [$current] : "; - $tmp = trim(fgets(STDIN, 1024)); - if ($tmp !== '') { - $result[$var] = $tmp; - } - } elseif ($tmp == 'all') { - foreach ($prompts as $var => $desc) { - $current = $result[$var]; - print "$desc [$current] : "; - $tmp = trim(fgets(STDIN, 1024)); - if (trim($tmp) !== '') { - $result[$var] = trim($tmp); - } - } - } - - $first_run = false; - } - - return $result; - } - - function userConfirm($prompt, $default = 'yes') - { - trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); - static $positives = array('y', 'yes', 'on', '1'); - static $negatives = array('n', 'no', 'off', '0'); - print "$this->lp$prompt [$default] : "; - $fp = fopen("php://stdin", "r"); - $line = fgets($fp, 2048); - fclose($fp); - $answer = strtolower(trim($line)); - if (empty($answer)) { - $answer = $default; - } - if (in_array($answer, $positives)) { - return true; - } - if (in_array($answer, $negatives)) { - return false; - } - if (in_array($default, $positives)) { - return true; - } - return false; - } - - function outputData($data, $command = '_default') - { - switch ($command) { - case 'channel-info': - foreach ($data as $type => $section) { - if ($type == 'main') { - $section['data'] = array_values($section['data']); - } - - $this->outputData($section); - } - break; - case 'install': - case 'upgrade': - case 'upgrade-all': - if (isset($data['release_warnings'])) { - $this->_displayLine(''); - $this->_startTable(array( - 'border' => false, - 'caption' => 'Release Warnings' - )); - $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); - $this->_endTable(); - $this->_displayLine(''); - } - - $this->_displayLine($data['data']); - break; - case 'search': - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); - } - - foreach($data['data'] as $category) { - foreach($category as $pkg) { - $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); - } - } - - $this->_endTable(); - break; - case 'list-all': - if (!isset($data['data'])) { - $this->_displayLine('No packages in channel'); - break; - } - - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); - } - - foreach($data['data'] as $category) { - foreach($category as $pkg) { - unset($pkg[4], $pkg[5]); - $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); - } - } - - $this->_endTable(); - break; - case 'config-show': - $data['border'] = false; - $opts = array( - 0 => array('wrap' => 30), - 1 => array('wrap' => 20), - 2 => array('wrap' => 35) - ); - - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), $opts); - } - - foreach ($data['data'] as $group) { - foreach ($group as $value) { - if ($value[2] == '') { - $value[2] = ""; - } - - $this->_tableRow($value, null, $opts); - } - } - - $this->_endTable(); - break; - case 'remote-info': - $d = $data; - $data = array( - 'caption' => 'Package details:', - 'border' => false, - 'data' => array( - array("Latest", $data['stable']), - array("Installed", $data['installed']), - array("Package", $data['name']), - array("License", $data['license']), - array("Category", $data['category']), - array("Summary", $data['summary']), - array("Description", $data['description']), - ), - ); - - if (isset($d['deprecated']) && $d['deprecated']) { - $conf = &PEAR_Config::singleton(); - $reg = $conf->getRegistry(); - $name = $reg->parsedPackageNameToString($d['deprecated'], true); - $data['data'][] = array('Deprecated! use', $name); - } - default: { - if (is_array($data)) { - $this->_startTable($data); - $count = count($data['data'][0]); - if ($count == 2) { - $opts = array(0 => array('wrap' => 25), - 1 => array('wrap' => 48) - ); - } elseif ($count == 3) { - $opts = array(0 => array('wrap' => 30), - 1 => array('wrap' => 20), - 2 => array('wrap' => 35) - ); - } else { - $opts = null; - } - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], - array('bold' => true), - $opts); - } - - foreach($data['data'] as $row) { - $this->_tableRow($row, null, $opts); - } - $this->_endTable(); - } else { - $this->_displayLine($data); - } - } - } - } - - function log($text, $append_crlf = true) - { - if ($append_crlf) { - return $this->_displayLine($text); - } - - return $this->_display($text); - } - - function bold($text) - { - if (empty($this->term['bold'])) { - return strtoupper($text); - } - - return $this->term['bold'] . $text . $this->term['normal']; - } - - function _displayHeading($title) - { - print $this->lp.$this->bold($title)."\n"; - print $this->lp.str_repeat("=", strlen($title))."\n"; - } - - function _startTable($params = array()) - { - $params['table_data'] = array(); - $params['widest'] = array(); // indexed by column - $params['highest'] = array(); // indexed by row - $params['ncols'] = 0; - $this->params = $params; - } - - function _tableRow($columns, $rowparams = array(), $colparams = array()) - { - $highest = 1; - for ($i = 0; $i < count($columns); $i++) { - $col = &$columns[$i]; - if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { - $col = wordwrap($col, $colparams[$i]['wrap']); - } - - if (strpos($col, "\n") !== false) { - $multiline = explode("\n", $col); - $w = 0; - foreach ($multiline as $n => $line) { - $len = strlen($line); - if ($len > $w) { - $w = $len; - } - } - $lines = count($multiline); - } else { - $w = strlen($col); - } - - if (isset($this->params['widest'][$i])) { - if ($w > $this->params['widest'][$i]) { - $this->params['widest'][$i] = $w; - } - } else { - $this->params['widest'][$i] = $w; - } - - $tmp = count_chars($columns[$i], 1); - // handle unix, mac and windows formats - $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; - if ($lines > $highest) { - $highest = $lines; - } - } - - if (count($columns) > $this->params['ncols']) { - $this->params['ncols'] = count($columns); - } - - $new_row = array( - 'data' => $columns, - 'height' => $highest, - 'rowparams' => $rowparams, - 'colparams' => $colparams, - ); - $this->params['table_data'][] = $new_row; - } - - function _endTable() - { - extract($this->params); - if (!empty($caption)) { - $this->_displayHeading($caption); - } - - if (count($table_data) === 0) { - return; - } - - if (!isset($width)) { - $width = $widest; - } else { - for ($i = 0; $i < $ncols; $i++) { - if (!isset($width[$i])) { - $width[$i] = $widest[$i]; - } - } - } - - $border = false; - if (empty($border)) { - $cellstart = ''; - $cellend = ' '; - $rowend = ''; - $padrowend = false; - $borderline = ''; - } else { - $cellstart = '| '; - $cellend = ' '; - $rowend = '|'; - $padrowend = true; - $borderline = '+'; - foreach ($width as $w) { - $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); - $borderline .= '+'; - } - } - - if ($borderline) { - $this->_displayLine($borderline); - } - - for ($i = 0; $i < count($table_data); $i++) { - extract($table_data[$i]); - if (!is_array($rowparams)) { - $rowparams = array(); - } - - if (!is_array($colparams)) { - $colparams = array(); - } - - $rowlines = array(); - if ($height > 1) { - for ($c = 0; $c < count($data); $c++) { - $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); - if (count($rowlines[$c]) < $height) { - $rowlines[$c] = array_pad($rowlines[$c], $height, ''); - } - } - } else { - for ($c = 0; $c < count($data); $c++) { - $rowlines[$c] = array($data[$c]); - } - } - - for ($r = 0; $r < $height; $r++) { - $rowtext = ''; - for ($c = 0; $c < count($data); $c++) { - if (isset($colparams[$c])) { - $attribs = array_merge($rowparams, $colparams); - } else { - $attribs = $rowparams; - } - - $w = isset($width[$c]) ? $width[$c] : 0; - //$cell = $data[$c]; - $cell = $rowlines[$c][$r]; - $l = strlen($cell); - if ($l > $w) { - $cell = substr($cell, 0, $w); - } - - if (isset($attribs['bold'])) { - $cell = $this->bold($cell); - } - - if ($l < $w) { - // not using str_pad here because we may - // add bold escape characters to $cell - $cell .= str_repeat(' ', $w - $l); - } - - $rowtext .= $cellstart . $cell . $cellend; - } - - if (!$border) { - $rowtext = rtrim($rowtext); - } - - $rowtext .= $rowend; - $this->_displayLine($rowtext); - } - } - - if ($borderline) { - $this->_displayLine($borderline); - } - } - - function _displayLine($text) - { - print "$this->lp$text\n"; - } - - function _display($text) - { - print $text; - } -}PEAR-1.9.0/PEAR/Installer/Role/Common.php100664 764 764 14233 100664 12657 - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class for all installation roles. - * - * This class allows extensibility of file roles. Packages with complex - * customization can now provide custom file roles along with the possibility of - * adding configuration values to match. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Common -{ - /** - * @var PEAR_Config - * @access protected - */ - var $config; - - /** - * @param PEAR_Config - */ - function PEAR_Installer_Role_Common(&$config) - { - $this->config = $config; - } - - /** - * Retrieve configuration information about a file role from its XML info - * - * @param string $role Role Classname, as in "PEAR_Installer_Role_Data" - * @return array - */ - function getInfo($role) - { - if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) { - return PEAR::raiseError('Unknown Role class: "' . $role . '"'); - } - return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role]; - } - - /** - * This is called for each file to set up the directories and files - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array attributes from the tag - * @param string file name - * @return array an array consisting of: - * - * 1 the original, pre-baseinstalldir installation directory - * 2 the final installation directory - * 3 the full path to the final location of the file - * 4 the location of the pre-installation file - */ - function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - if (!$roleInfo['locationconfig']) { - return false; - } - if ($roleInfo['honorsbaseinstall']) { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer, - $pkg->getChannel()); - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - } elseif ($roleInfo['unusualbaseinstall']) { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], - $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - } else { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], - $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); - } - if (dirname($file) != '.' && empty($atts['install-as'])) { - $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); - } - if (empty($atts['install-as'])) { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); - } else { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; - } - $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; - - // Clean up the DIRECTORY_SEPARATOR mess - $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; - - list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR), - array($dest_dir, $dest_file, $orig_file)); - return array($save_destdir, $dest_dir, $dest_file, $orig_file); - } - - /** - * Get the name of the configuration variable that specifies the location of this file - * @return string|false - */ - function getLocationConfig() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['locationconfig']; - } - - /** - * Do any unusual setup here - * @param PEAR_Installer - * @param PEAR_PackageFile_v2 - * @param array file attributes - * @param string file name - */ - function setup(&$installer, $pkg, $atts, $file) - { - } - - function isExecutable() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['executable']; - } - - function isInstallable() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['installable']; - } - - function isExtension() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['phpextension']; - } -} -?>PEAR-1.9.0/PEAR/Installer/Role/Cfg.xml100664 764 764 645 100664 12101 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - cfg_dir - - 1 - - - - -PEAR-1.9.0/PEAR/Installer/Role/Cfg.php100664 764 764 7702 100664 12111 - * @copyright 2007-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Cfg.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.7.0 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 2007-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.7.0 - */ -class PEAR_Installer_Role_Cfg extends PEAR_Installer_Role_Common -{ - /** - * @var PEAR_Installer - */ - var $installer; - - /** - * the md5 of the original file - * - * @var unknown_type - */ - var $md5 = null; - - /** - * Do any unusual setup here - * @param PEAR_Installer - * @param PEAR_PackageFile_v2 - * @param array file attributes - * @param string file name - */ - function setup(&$installer, $pkg, $atts, $file) - { - $this->installer = &$installer; - $reg = &$this->installer->config->getRegistry(); - $package = $reg->getPackage($pkg->getPackage(), $pkg->getChannel()); - if ($package) { - $filelist = $package->getFilelist(); - if (isset($filelist[$file]) && isset($filelist[$file]['md5sum'])) { - $this->md5 = $filelist[$file]['md5sum']; - } - } - } - - function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) - { - $test = parent::processInstallation($pkg, $atts, $file, $tmp_path, $layer); - if (@file_exists($test[2]) && @file_exists($test[3])) { - $md5 = md5_file($test[2]); - // configuration has already been installed, check for mods - if ($md5 !== $this->md5 && $md5 !== md5_file($test[3])) { - // configuration has been modified, so save our version as - // configfile-version - $old = $test[2]; - $test[2] .= '.new-' . $pkg->getVersion(); - // backup original and re-install it - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $tmpcfg = $this->config->get('temp_dir'); - $newloc = System::mkdir(array('-p', $tmpcfg)); - if (!$newloc) { - // try temp_dir - $newloc = System::mktemp(array('-d')); - if (!$newloc || PEAR::isError($newloc)) { - PEAR::popErrorHandling(); - return PEAR::raiseError('Could not save existing configuration file '. - $old . ', unable to install. Please set temp_dir ' . - 'configuration variable to a writeable location and try again'); - } - } else { - $newloc = $tmpcfg; - } - - $temp_file = $newloc . DIRECTORY_SEPARATOR . uniqid('savefile'); - if (!@copy($old, $temp_file)) { - PEAR::popErrorHandling(); - return PEAR::raiseError('Could not save existing configuration file '. - $old . ', unable to install. Please set temp_dir ' . - 'configuration variable to a writeable location and try again'); - } - - PEAR::popErrorHandling(); - $this->installer->log(0, "WARNING: configuration file $old is being installed as $test[2], you should manually merge in changes to the existing configuration file"); - $this->installer->addFileOperation('rename', array($temp_file, $old, false)); - $this->installer->addFileOperation('delete', array($temp_file)); - } - } - - return $test; - } -}PEAR-1.9.0/PEAR/Installer/Role/Data.xml100664 764 764 622 100664 12246 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - data_dir - - - - - - -PEAR-1.9.0/PEAR/Installer/Role/Data.php100664 764 764 1523 100664 12256 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Data.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role/Doc.xml100664 764 764 621 100664 12101 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - doc_dir - - - - - - -PEAR-1.9.0/PEAR/Installer/Role/Doc.php100664 764 764 1520 100664 12107 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Doc.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role/Ext.xml100664 764 764 502 100664 12132 - extbin - zendextbin - 1 - ext_dir - 1 - - - - 1 - -PEAR-1.9.0/PEAR/Installer/Role/Ext.php100664 764 764 1520 100664 12142 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Ext.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role/Php.xml100664 764 764 655 100664 12132 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - php_dir - 1 - - 1 - - - -PEAR-1.9.0/PEAR/Installer/Role/Php.php100664 764 764 1520 100664 12131 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Php.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role/Script.xml100664 764 764 660 100664 12643 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - bin_dir - 1 - - - 1 - - -PEAR-1.9.0/PEAR/Installer/Role/Script.php100664 764 764 1531 100664 12650 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Script.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role/Src.xml100664 764 764 442 100664 12124 - extsrc - zendextsrc - 1 - temp_dir - - - - - - -PEAR-1.9.0/PEAR/Installer/Role/Src.php100664 764 764 1665 100664 12143 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Src.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common -{ - function setup(&$installer, $pkg, $atts, $file) - { - $installer->source_files++; - } -} -?>PEAR-1.9.0/PEAR/Installer/Role/Test.xml100664 764 764 622 100664 12314 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - test_dir - - - - - - -PEAR-1.9.0/PEAR/Installer/Role/Test.php100664 764 764 1523 100664 12324 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Test.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role/Www.xml100664 764 764 644 100664 12165 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - www_dir - 1 - - - - - -PEAR-1.9.0/PEAR/Installer/Role/Www.php100664 764 764 1514 100664 12171 - * @copyright 2007-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Www.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.7.0 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 2007-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.7.0 - */ -class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {} -?>PEAR-1.9.0/PEAR/Installer/Role.php100664 764 764 17464 100664 11440 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Role.php 278552 2009-04-10 19:42:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base class for installer roles - */ -require_once 'PEAR/Installer/Role/Common.php'; -require_once 'PEAR/XMLParser.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role -{ - /** - * Set up any additional configuration variables that file roles require - * - * Never call this directly, it is called by the PEAR_Config constructor - * @param PEAR_Config - * @access private - * @static - */ - function initializeConfig(&$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { - if (!$info['config_vars']) { - continue; - } - - $config->_addConfigVars($class, $info['config_vars']); - } - } - - /** - * @param PEAR_PackageFile_v2 - * @param string role name - * @param PEAR_Config - * @return PEAR_Installer_Role_Common - * @static - */ - function &factory($pkg, $role, &$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { - $a = false; - return $a; - } - - $a = 'PEAR_Installer_Role_' . ucfirst($role); - if (!class_exists($a)) { - require_once str_replace('_', '/', $a) . '.php'; - } - - $b = new $a($config); - return $b; - } - - /** - * Get a list of file roles that are valid for the particular release type. - * - * For instance, src files serve no purpose in regular php releases. - * @param string - * @param bool clear cache - * @return array - * @static - */ - function getValidRoles($release, $clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret = array(); - if ($clear) { - $ret = array(); - } - - if (isset($ret[$release])) { - return $ret[$release]; - } - - $ret[$release] = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if (in_array($release, $okreleases['releasetypes'])) { - $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret[$release]; - } - - /** - * Get a list of roles that require their files to be installed - * - * Most roles must be installed, but src and package roles, for instance - * are pseudo-roles. src files are compiled into a new extension. Package - * roles are actually fully bundled releases of a package - * @param bool clear cache - * @return array - * @static - */ - function getInstallableRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['installable']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of roles that are affected by the baseinstalldir attribute - * - * Most roles ignore this attribute, and instead install directly into: - * PackageName/filepath - * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php - * @param bool clear cache - * @return array - * @static - */ - function getBaseinstallRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['honorsbaseinstall']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of file roles that should be analyzed for PHP content at package time, - * like the "php" role. - * @param bool clear cache - * @return array - * @static - */ - function getPhpRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['phpfile']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * @param string which directory to look for classes, defaults to - * the Installer/Roles subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * @access public - * @static - */ - function registerRoles($dir = null) - { - $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Role'; - } - - if (!file_exists($dir) || !is_dir($dir)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); - } - - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); - } - - while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.xml') { - continue; - } - - $class = "PEAR_Installer_Role_".substr($entry, 0, -4); - // List of roles - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { - $file = "$dir/$entry"; - $parser->parse(file_get_contents($file)); - $data = $parser->getData(); - if (!is_array($data['releasetypes'])) { - $data['releasetypes'] = array($data['releasetypes']); - } - - $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; - } - } - - closedir($dp); - ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); - PEAR_Installer_Role::getBaseinstallRoles(true); - PEAR_Installer_Role::getInstallableRoles(true); - PEAR_Installer_Role::getPhpRoles(true); - PEAR_Installer_Role::getValidRoles('****', true); - return true; - } -}PEAR-1.9.0/PEAR/PackageFile/Generator/v1.php100664 764 764 142342 100664 13223 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php 286494 2009-07-29 06:57:11Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'PEAR/Validate.php'; -require_once 'System.php'; -require_once 'PEAR/PackageFile/v2.php'; -/** - * This class converts a PEAR_PackageFile_v1 object into any output format. - * - * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 - * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Generator_v1 -{ - /** - * @var PEAR_PackageFile_v1 - */ - var $_packagefile; - function PEAR_PackageFile_Generator_v1(&$packagefile) - { - $this->_packagefile = &$packagefile; - } - - function getPackagerVersion() - { - return '1.9.0'; - } - - /** - * @param PEAR_Packager - * @param bool if true, a .tgz is written, otherwise a .tar is written - * @param string|null directory in which to save the .tgz - * @return string|PEAR_Error location of package or error object - */ - function toTgz(&$packager, $compress = true, $where = null) - { - require_once 'Archive/Tar.php'; - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . - ' not be created'); - } - if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && - !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . - ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); - } - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); - } - $pkginfo = $this->_packagefile->getArray(); - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; - if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && - !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . - getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); - } - if ($pkgfile = $this->_packagefile->getPackageFile()) { - $pkgdir = dirname(realpath($pkgfile)); - $pkgfile = basename($pkgfile); - } else { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' . - 'be created from a real file'); - } - // {{{ Create the package file list - $filelist = array(); - $i = 0; - - foreach ($this->_packagefile->getFilelist() as $fname => $atts) { - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return PEAR::raiseError("File does not exist: $fname"); - } else { - $filelist[$i++] = $file; - if (!isset($atts['md5sum'])) { - $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file)); - } - $packager->log(2, "Adding file $fname"); - } - } - // }}} - $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); - if ($packagexml) { - $tar =& new Archive_Tar($dest_package, $compress); - $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors - // ----- Creates with the package.xml file - $ok = $tar->createModify(array($packagexml), '', $where); - if (PEAR::isError($ok)) { - return $ok; - } elseif (!$ok) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); - } - // ----- Add the content of the package - if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); - } - return $dest_package; - } - } - - /** - * @param string|null directory to place the package.xml in, or null for a temporary dir - * @param int one of the PEAR_VALIDATE_* constants - * @param string name of the generated file - * @param bool if true, then no analysis will be performed on role="php" files - * @return string|PEAR_Error path to the created file on success - */ - function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml', - $nofilechecking = false) - { - if (!$this->_packagefile->validate($state, $nofilechecking)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml', - null, null, null, $this->_packagefile->getValidationWarnings()); - } - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' . - ' not be created'); - } - $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; - $np = @fopen($newpkgfile, 'wb'); - if (!$np) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' . - "$name as $newpkgfile"); - } - fwrite($np, $this->toXml($state, true)); - fclose($np); - return $newpkgfile; - } - - /** - * fix both XML encoding to be UTF8, and replace standard XML entities < > " & ' - * - * @param string $string - * @return string - * @access private - */ - function _fixXmlEncoding($string) - { - if (version_compare(phpversion(), '5.0.0', 'lt')) { - $string = utf8_encode($string); - } - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - '\'' => ''' )); - } - - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @return string XML data - */ - function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false) - { - $this->_packagefile->setDate(date('Y-m-d')); - if (!$this->_packagefile->validate($state, $nofilevalidation)) { - return false; - } - $pkginfo = $this->_packagefile->getArray(); - static $maint_map = array( - "handle" => "user", - "name" => "name", - "email" => "email", - "role" => "role", - ); - $ret = "\n"; - $ret .= "\n"; - $ret .= "\n" . -" $pkginfo[package]"; - if (isset($pkginfo['extends'])) { - $ret .= "\n$pkginfo[extends]"; - } - $ret .= - "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" . -" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" . -" \n"; - foreach ($pkginfo['maintainers'] as $maint) { - $ret .= " \n"; - foreach ($maint_map as $idx => $elm) { - $ret .= " <$elm>"; - $ret .= $this->_fixXmlEncoding($maint[$idx]); - $ret .= "\n"; - } - $ret .= " \n"; - } - $ret .= " \n"; - $ret .= $this->_makeReleaseXml($pkginfo, false, $state); - if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) { - $ret .= " \n"; - foreach ($pkginfo['changelog'] as $oldrelease) { - $ret .= $this->_makeReleaseXml($oldrelease, true); - } - $ret .= " \n"; - } - $ret .= "\n"; - return $ret; - } - - // }}} - // {{{ _makeReleaseXml() - - /** - * Generate part of an XML description with release information. - * - * @param array $pkginfo array with release information - * @param bool $changelog whether the result will be in a changelog element - * - * @return string XML data - * - * @access private - */ - function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL) - { - // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! - $indent = $changelog ? " " : ""; - $ret = "$indent \n"; - if (!empty($pkginfo['version'])) { - $ret .= "$indent $pkginfo[version]\n"; - } - if (!empty($pkginfo['release_date'])) { - $ret .= "$indent $pkginfo[release_date]\n"; - } - if (!empty($pkginfo['release_license'])) { - $ret .= "$indent $pkginfo[release_license]\n"; - } - if (!empty($pkginfo['release_state'])) { - $ret .= "$indent $pkginfo[release_state]\n"; - } - if (!empty($pkginfo['release_notes'])) { - $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes'])) - ."\n$indent \n"; - } - if (!empty($pkginfo['release_warnings'])) { - $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n"; - } - if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { - $ret .= "$indent \n"; - foreach ($pkginfo['release_deps'] as $dep) { - $ret .= "$indent _fixXmlEncoding($c['name']) . "\""; - if (isset($c['default'])) { - $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\""; - } - $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\""; - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - if (isset($pkginfo['provides'])) { - foreach ($pkginfo['provides'] as $key => $what) { - $ret .= "$indent recursiveXmlFilelist($pkginfo['filelist']); - } else { - foreach ($pkginfo['filelist'] as $file => $fa) { - if (!isset($fa['role'])) { - $fa['role'] = ''; - } - $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"'; - } - if (isset($fa['md5sum'])) { - $ret .= " md5sum=\"$fa[md5sum]\""; - } - if (isset($fa['platform'])) { - $ret .= " platform=\"$fa[platform]\""; - } - if (!empty($fa['install-as'])) { - $ret .= ' install-as="' . - $this->_fixXmlEncoding($fa['install-as']) . '"'; - } - $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; - if (empty($fa['replacements'])) { - $ret .= "/>\n"; - } else { - $ret .= ">\n"; - foreach ($fa['replacements'] as $r) { - $ret .= "$indent $v) { - $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; - } - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - } - } - $ret .= "$indent \n"; - } - $ret .= "$indent \n"; - return $ret; - } - - /** - * @param array - * @access protected - */ - function recursiveXmlFilelist($list) - { - $this->_dirs = array(); - foreach ($list as $file => $attributes) { - $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); - } - return $this->_formatDir($this->_dirs); - } - - /** - * @param array - * @param array - * @param string|null - * @param array|null - * @access private - */ - function _addDir(&$dirs, $dir, $file = null, $attributes = null) - { - if ($dir == array() || $dir == array('.')) { - $dirs['files'][basename($file)] = $attributes; - return; - } - $curdir = array_shift($dir); - if (!isset($dirs['dirs'][$curdir])) { - $dirs['dirs'][$curdir] = array(); - } - $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); - } - - /** - * @param array - * @param string - * @param string - * @access private - */ - function _formatDir($dirs, $indent = '', $curdir = '') - { - $ret = ''; - if (!count($dirs)) { - return ''; - } - if (isset($dirs['dirs'])) { - uksort($dirs['dirs'], 'strnatcasecmp'); - foreach ($dirs['dirs'] as $dir => $contents) { - $usedir = "$curdir/$dir"; - $ret .= "$indent \n"; - $ret .= $this->_formatDir($contents, "$indent ", $usedir); - $ret .= "$indent \n"; - } - } - if (isset($dirs['files'])) { - uksort($dirs['files'], 'strnatcasecmp'); - foreach ($dirs['files'] as $file => $attribs) { - $ret .= $this->_formatFile($file, $attribs, $indent); - } - } - return $ret; - } - - /** - * @param string - * @param array - * @param string - * @access private - */ - function _formatFile($file, $attributes, $indent) - { - $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"'; - } - if (isset($attributes['md5sum'])) { - $ret .= " md5sum=\"$attributes[md5sum]\""; - } - if (isset($attributes['platform'])) { - $ret .= " platform=\"$attributes[platform]\""; - } - if (!empty($attributes['install-as'])) { - $ret .= ' install-as="' . - $this->_fixXmlEncoding($attributes['install-as']) . '"'; - } - $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; - if (empty($attributes['replacements'])) { - $ret .= "/>\n"; - } else { - $ret .= ">\n"; - foreach ($attributes['replacements'] as $r) { - $ret .= "$indent $v) { - $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; - } - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - return $ret; - } - - // {{{ _unIndent() - - /** - * Unindent given string (?) - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } - } - return $data; - } - - /** - * @return array - */ - function dependenciesToV2() - { - $arr = array(); - $this->_convertDependencies2_0($arr); - return $arr['dependencies']; - } - - /** - * Convert a package.xml version 1.0 into version 2.0 - * - * Note that this does a basic conversion, to allow more advanced - * features like bundles and multiple releases - * @param string the classname to instantiate and return. This must be - * PEAR_PackageFile_v2 or a descendant - * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the - * strictest parameters will be converted - * @return PEAR_PackageFile_v2|PEAR_Error - */ - function &toV2($class = 'PEAR_PackageFile_v2', $strict = false) - { - if ($strict) { - if (!$this->_packagefile->validate()) { - $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' . - ' to version 2.0', null, null, null, - $this->_packagefile->getValidationWarnings(true)); - return $a; - } - } - - $arr = array( - 'attribs' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" . -"http://pear.php.net/dtd/tasks-1.0.xsd\n" . -"http://pear.php.net/dtd/package-2.0\n" . -'http://pear.php.net/dtd/package-2.0.xsd', - ), - 'name' => $this->_packagefile->getPackage(), - 'channel' => 'pear.php.net', - ); - $arr['summary'] = $this->_packagefile->getSummary(); - $arr['description'] = $this->_packagefile->getDescription(); - $maintainers = $this->_packagefile->getMaintainers(); - foreach ($maintainers as $maintainer) { - if ($maintainer['role'] != 'lead') { - continue; - } - $new = array( - 'name' => $maintainer['name'], - 'user' => $maintainer['handle'], - 'email' => $maintainer['email'], - 'active' => 'yes', - ); - $arr['lead'][] = $new; - } - - if (!isset($arr['lead'])) { // some people... you know? - $arr['lead'] = array( - 'name' => 'unknown', - 'user' => 'unknown', - 'email' => 'noleadmaintainer@example.com', - 'active' => 'no', - ); - } - - if (count($arr['lead']) == 1) { - $arr['lead'] = $arr['lead'][0]; - } - - foreach ($maintainers as $maintainer) { - if ($maintainer['role'] == 'lead') { - continue; - } - $new = array( - 'name' => $maintainer['name'], - 'user' => $maintainer['handle'], - 'email' => $maintainer['email'], - 'active' => 'yes', - ); - $arr[$maintainer['role']][] = $new; - } - - if (isset($arr['developer']) && count($arr['developer']) == 1) { - $arr['developer'] = $arr['developer'][0]; - } - - if (isset($arr['contributor']) && count($arr['contributor']) == 1) { - $arr['contributor'] = $arr['contributor'][0]; - } - - if (isset($arr['helper']) && count($arr['helper']) == 1) { - $arr['helper'] = $arr['helper'][0]; - } - - $arr['date'] = $this->_packagefile->getDate(); - $arr['version'] = - array( - 'release' => $this->_packagefile->getVersion(), - 'api' => $this->_packagefile->getVersion(), - ); - $arr['stability'] = - array( - 'release' => $this->_packagefile->getState(), - 'api' => $this->_packagefile->getState(), - ); - $licensemap = - array( - 'php' => 'http://www.php.net/license', - 'php license' => 'http://www.php.net/license', - 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html', - 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php', - 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php', - 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php', - 'mit' => 'http://www.opensource.org/licenses/mit-license.php', - 'gpl' => 'http://www.gnu.org/copyleft/gpl.html', - 'apache' => 'http://www.opensource.org/licenses/apache2.0.php' - ); - - if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) { - $arr['license'] = array( - 'attribs' => array('uri' => - $licensemap[strtolower($this->_packagefile->getLicense())]), - '_content' => $this->_packagefile->getLicense() - ); - } else { - // don't use bogus uri - $arr['license'] = $this->_packagefile->getLicense(); - } - - $arr['notes'] = $this->_packagefile->getNotes(); - $temp = array(); - $arr['contents'] = $this->_convertFilelist2_0($temp); - $this->_convertDependencies2_0($arr); - $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ? - 'extsrcrelease' : 'phprelease'; - if ($release == 'extsrcrelease') { - $arr['channel'] = 'pecl.php.net'; - $arr['providesextension'] = $arr['name']; // assumption - } - - $arr[$release] = array(); - if ($this->_packagefile->getConfigureOptions()) { - $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions(); - foreach ($arr[$release]['configureoption'] as $i => $opt) { - $arr[$release]['configureoption'][$i] = array('attribs' => $opt); - } - if (count($arr[$release]['configureoption']) == 1) { - $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0]; - } - } - - $this->_convertRelease2_0($arr[$release], $temp); - if ($release == 'extsrcrelease' && count($arr[$release]) > 1) { - // multiple extsrcrelease tags added in PEAR 1.4.1 - $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1'; - } - - if ($cl = $this->_packagefile->getChangelog()) { - foreach ($cl as $release) { - $rel = array(); - $rel['version'] = - array( - 'release' => $release['version'], - 'api' => $release['version'], - ); - if (!isset($release['release_state'])) { - $release['release_state'] = 'stable'; - } - - $rel['stability'] = - array( - 'release' => $release['release_state'], - 'api' => $release['release_state'], - ); - if (isset($release['release_date'])) { - $rel['date'] = $release['release_date']; - } else { - $rel['date'] = date('Y-m-d'); - } - - if (isset($release['release_license'])) { - if (isset($licensemap[strtolower($release['release_license'])])) { - $uri = $licensemap[strtolower($release['release_license'])]; - } else { - $uri = 'http://www.example.com'; - } - $rel['license'] = array( - 'attribs' => array('uri' => $uri), - '_content' => $release['release_license'] - ); - } else { - $rel['license'] = $arr['license']; - } - - if (!isset($release['release_notes'])) { - $release['release_notes'] = 'no release notes'; - } - - $rel['notes'] = $release['release_notes']; - $arr['changelog']['release'][] = $rel; - } - } - - $ret = new $class; - $ret->setConfig($this->_packagefile->_config); - if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) { - $ret->setLogger($this->_packagefile->_logger); - } - - $ret->fromArray($arr); - return $ret; - } - - /** - * @param array - * @param bool - * @access private - */ - function _convertDependencies2_0(&$release, $internal = false) - { - $peardep = array('pearinstaller' => - array('min' => '1.4.0b1')); // this is a lot safer - $required = $optional = array(); - $release['dependencies'] = array('required' => array()); - if ($this->_packagefile->hasDeps()) { - foreach ($this->_packagefile->getDeps() as $dep) { - if (!isset($dep['optional']) || $dep['optional'] == 'no') { - $required[] = $dep; - } else { - $optional[] = $dep; - } - } - foreach (array('required', 'optional') as $arr) { - $deps = array(); - foreach ($$arr as $dep) { - // organize deps by dependency type and name - if (!isset($deps[$dep['type']])) { - $deps[$dep['type']] = array(); - } - if (isset($dep['name'])) { - $deps[$dep['type']][$dep['name']][] = $dep; - } else { - $deps[$dep['type']][] = $dep; - } - } - do { - if (isset($deps['php'])) { - $php = array(); - if (count($deps['php']) > 1) { - $php = $this->_processPhpDeps($deps['php']); - } else { - if (!isset($deps['php'][0])) { - list($key, $blah) = each ($deps['php']); // stupid buggy versions - $deps['php'] = array($blah[0]); - } - $php = $this->_processDep($deps['php'][0]); - if (!$php) { - break; // poor mans throw - } - } - $release['dependencies'][$arr]['php'] = $php; - } - } while (false); - do { - if (isset($deps['pkg'])) { - $pkg = array(); - $pkg = $this->_processMultipleDepsName($deps['pkg']); - if (!$pkg) { - break; // poor mans throw - } - $release['dependencies'][$arr]['package'] = $pkg; - } - } while (false); - do { - if (isset($deps['ext'])) { - $pkg = array(); - $pkg = $this->_processMultipleDepsName($deps['ext']); - $release['dependencies'][$arr]['extension'] = $pkg; - } - } while (false); - // skip sapi - it's not supported so nobody will have used it - // skip os - it's not supported in 1.0 - } - } - if (isset($release['dependencies']['required'])) { - $release['dependencies']['required'] = - array_merge($peardep, $release['dependencies']['required']); - } else { - $release['dependencies']['required'] = $peardep; - } - if (!isset($release['dependencies']['required']['php'])) { - $release['dependencies']['required']['php'] = - array('min' => '4.0.0'); - } - $order = array(); - $bewm = $release['dependencies']['required']; - $order['php'] = $bewm['php']; - $order['pearinstaller'] = $bewm['pearinstaller']; - isset($bewm['package']) ? $order['package'] = $bewm['package'] :0; - isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0; - $release['dependencies']['required'] = $order; - } - - /** - * @param array - * @access private - */ - function _convertFilelist2_0(&$package) - { - $ret = array('dir' => - array( - 'attribs' => array('name' => '/'), - 'file' => array() - ) - ); - $package['platform'] = - $package['install-as'] = array(); - $this->_isExtension = false; - foreach ($this->_packagefile->getFilelist() as $name => $file) { - $file['name'] = $name; - if (isset($file['role']) && $file['role'] == 'src') { - $this->_isExtension = true; - } - if (isset($file['replacements'])) { - $repl = $file['replacements']; - unset($file['replacements']); - } else { - unset($repl); - } - if (isset($file['install-as'])) { - $package['install-as'][$name] = $file['install-as']; - unset($file['install-as']); - } - if (isset($file['platform'])) { - $package['platform'][$name] = $file['platform']; - unset($file['platform']); - } - $file = array('attribs' => $file); - if (isset($repl)) { - foreach ($repl as $replace ) { - $file['tasks:replace'][] = array('attribs' => $replace); - } - if (count($repl) == 1) { - $file['tasks:replace'] = $file['tasks:replace'][0]; - } - } - $ret['dir']['file'][] = $file; - } - return $ret; - } - - /** - * Post-process special files with install-as/platform attributes and - * make the release tag. - * - * This complex method follows this work-flow to create the release tags: - * - *
    -     * - if any install-as/platform exist, create a generic release and fill it with
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     * - create a release for each platform encountered and fill with
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     * 
    - * - * It does this by accessing the $package parameter, which contains an array with - * indices: - * - * - platform: mapping of file => OS the file should be installed on - * - install-as: mapping of file => installed name - * - osmap: mapping of OS => list of files that should be installed - * on that OS - * - notosmap: mapping of OS => list of files that should not be - * installed on that OS - * - * @param array - * @param array - * @access private - */ - function _convertRelease2_0(&$release, $package) - { - //- if any install-as/platform exist, create a generic release and fill it with - if (count($package['platform']) || count($package['install-as'])) { - $generic = array(); - $genericIgnore = array(); - foreach ($package['install-as'] as $file => $as) { - //o tags for - if (!isset($package['platform'][$file])) { - $generic[] = $file; - continue; - } - //o tags for - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} == '!') { - $generic[] = $file; - continue; - } - //o tags for - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} != '!') { - $genericIgnore[] = $file; - continue; - } - } - foreach ($package['platform'] as $file => $platform) { - if (isset($package['install-as'][$file])) { - continue; - } - if ($platform{0} != '!') { - //o tags for - $genericIgnore[] = $file; - } - } - if (count($package['platform'])) { - $oses = $notplatform = $platform = array(); - foreach ($package['platform'] as $file => $os) { - // get a list of oses - if ($os{0} == '!') { - if (isset($oses[substr($os, 1)])) { - continue; - } - $oses[substr($os, 1)] = count($oses); - } else { - if (isset($oses[$os])) { - continue; - } - $oses[$os] = count($oses); - } - } - //- create a release for each platform encountered and fill with - foreach ($oses as $os => $releaseNum) { - $release[$releaseNum]['installconditions']['os']['name'] = $os; - $release[$releaseNum]['filelist'] = array('install' => array(), - 'ignore' => array()); - foreach ($package['install-as'] as $file => $as) { - //o tags for - if (!isset($package['platform'][$file])) { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] == $os) { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] != "!$os" && - $package['platform'][$file]{0} == '!') { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] == "!$os") { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} != '!' && - $package['platform'][$file] != $os) { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - } - foreach ($package['platform'] as $file => $platform) { - if (isset($package['install-as'][$file])) { - continue; - } - //o tags for - if ($platform == "!$os") { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - //o tags for - if ($platform{0} != '!' && $platform != $os) { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - } - } - if (!count($release[$releaseNum]['filelist']['install'])) { - unset($release[$releaseNum]['filelist']['install']); - } - if (!count($release[$releaseNum]['filelist']['ignore'])) { - unset($release[$releaseNum]['filelist']['ignore']); - } - } - if (count($generic) || count($genericIgnore)) { - $release[count($oses)] = array(); - if (count($generic)) { - foreach ($generic as $file) { - if (isset($package['install-as'][$file])) { - $installas = $package['install-as'][$file]; - } else { - $installas = $file; - } - $release[count($oses)]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $installas, - ) - ); - } - } - if (count($genericIgnore)) { - foreach ($genericIgnore as $file) { - $release[count($oses)]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ) - ); - } - } - } - // cleanup - foreach ($release as $i => $rel) { - if (isset($rel['filelist']['install']) && - count($rel['filelist']['install']) == 1) { - $release[$i]['filelist']['install'] = - $release[$i]['filelist']['install'][0]; - } - if (isset($rel['filelist']['ignore']) && - count($rel['filelist']['ignore']) == 1) { - $release[$i]['filelist']['ignore'] = - $release[$i]['filelist']['ignore'][0]; - } - } - if (count($release) == 1) { - $release = $release[0]; - } - } else { - // no platform atts, but some install-as atts - foreach ($package['install-as'] as $file => $value) { - $release['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $value - ) - ); - } - if (count($release['filelist']['install']) == 1) { - $release['filelist']['install'] = $release['filelist']['install'][0]; - } - } - } - } - - /** - * @param array - * @return array - * @access private - */ - function _processDep($dep) - { - if ($dep['type'] == 'php') { - if ($dep['rel'] == 'has') { - // come on - everyone has php! - return false; - } - } - $php = array(); - if ($dep['type'] != 'php') { - $php['name'] = $dep['name']; - if ($dep['type'] == 'pkg') { - $php['channel'] = 'pear.php.net'; - } - } - switch ($dep['rel']) { - case 'gt' : - $php['min'] = $dep['version']; - $php['exclude'] = $dep['version']; - break; - case 'ge' : - if (!isset($dep['version'])) { - if ($dep['type'] == 'php') { - if (isset($dep['name'])) { - $dep['version'] = $dep['name']; - } - } - } - $php['min'] = $dep['version']; - break; - case 'lt' : - $php['max'] = $dep['version']; - $php['exclude'] = $dep['version']; - break; - case 'le' : - $php['max'] = $dep['version']; - break; - case 'eq' : - $php['min'] = $dep['version']; - $php['max'] = $dep['version']; - break; - case 'ne' : - $php['exclude'] = $dep['version']; - break; - case 'not' : - $php['conflicts'] = 'yes'; - break; - } - return $php; - } - - /** - * @param array - * @return array - */ - function _processPhpDeps($deps) - { - $test = array(); - foreach ($deps as $dep) { - $test[] = $this->_processDep($dep); - } - $min = array(); - $max = array(); - foreach ($test as $dep) { - if (!$dep) { - continue; - } - if (isset($dep['min'])) { - $min[$dep['min']] = count($min); - } - if (isset($dep['max'])) { - $max[$dep['max']] = count($max); - } - } - if (count($min) > 0) { - uksort($min, 'version_compare'); - } - if (count($max) > 0) { - uksort($max, 'version_compare'); - } - if (count($min)) { - // get the highest minimum - $min = array_pop($a = array_flip($min)); - } else { - $min = false; - } - if (count($max)) { - // get the lowest maximum - $max = array_shift($a = array_flip($max)); - } else { - $max = false; - } - if ($min) { - $php['min'] = $min; - } - if ($max) { - $php['max'] = $max; - } - $exclude = array(); - foreach ($test as $dep) { - if (!isset($dep['exclude'])) { - continue; - } - $exclude[] = $dep['exclude']; - } - if (count($exclude)) { - $php['exclude'] = $exclude; - } - return $php; - } - - /** - * process multiple dependencies that have a name, like package deps - * @param array - * @return array - * @access private - */ - function _processMultipleDepsName($deps) - { - $ret = $tests = array(); - foreach ($deps as $name => $dep) { - foreach ($dep as $d) { - $tests[$name][] = $this->_processDep($d); - } - } - - foreach ($tests as $name => $test) { - $max = $min = $php = array(); - $php['name'] = $name; - foreach ($test as $dep) { - if (!$dep) { - continue; - } - if (isset($dep['channel'])) { - $php['channel'] = 'pear.php.net'; - } - if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') { - $php['conflicts'] = 'yes'; - } - if (isset($dep['min'])) { - $min[$dep['min']] = count($min); - } - if (isset($dep['max'])) { - $max[$dep['max']] = count($max); - } - } - if (count($min) > 0) { - uksort($min, 'version_compare'); - } - if (count($max) > 0) { - uksort($max, 'version_compare'); - } - if (count($min)) { - // get the highest minimum - $min = array_pop($a = array_flip($min)); - } else { - $min = false; - } - if (count($max)) { - // get the lowest maximum - $max = array_shift($a = array_flip($max)); - } else { - $max = false; - } - if ($min) { - $php['min'] = $min; - } - if ($max) { - $php['max'] = $max; - } - $exclude = array(); - foreach ($test as $dep) { - if (!isset($dep['exclude'])) { - continue; - } - $exclude[] = $dep['exclude']; - } - if (count($exclude)) { - $php['exclude'] = $exclude; - } - $ret[] = $php; - } - return $ret; - } -} -?>PEAR-1.9.0/PEAR/PackageFile/Generator/v2.php100664 764 764 101360 100664 13217 - * @author Stephan Schmidt (original XML_Serializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php 278907 2009-04-17 21:10:04Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * file/dir manipulation routines - */ -require_once 'System.php'; -require_once 'XML/Util.php'; - -/** - * This class converts a PEAR_PackageFile_v2 object into any output format. - * - * Supported output formats include array, XML string (using S. Schmidt's - * XML_Serializer, slightly customized) - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stephan Schmidt (original XML_Serializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Generator_v2 -{ - /** - * default options for the serialization - * @access private - * @var array $_defaultOptions - */ - var $_defaultOptions = array( - 'indent' => ' ', // string used for indentation - 'linebreak' => "\n", // string used for newlines - 'typeHints' => false, // automatically add type hin attributes - 'addDecl' => true, // add an XML declaration - 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names - 'classAsTagName' => false, // use classname for objects in indexed arrays - 'keyAttribute' => '_originalKey', // attribute where original key is stored - 'typeAttribute' => '_type', // attribute for type (only if typeHints => true) - 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true) - 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute - 'prependAttributes' => '', // prepend string for attributes - 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column - 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array - 'addDoctype' => false, // add a doctype declaration - 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()} - 'rootName' => 'package', // name of the root tag - 'rootAttributes' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 -http://pear.php.net/dtd/tasks-1.0.xsd -http://pear.php.net/dtd/package-2.0 -http://pear.php.net/dtd/package-2.0.xsd', - ), // attributes of the root tag - 'attributesArray' => 'attribs', // all values in this key will be treated as attributes - 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray - 'beautifyFilelist' => false, - 'encoding' => 'UTF-8', - ); - - /** - * options for the serialization - * @access private - * @var array $options - */ - var $options = array(); - - /** - * current tag depth - * @var integer $_tagDepth - */ - var $_tagDepth = 0; - - /** - * serilialized representation of the data - * @var string $_serializedData - */ - var $_serializedData = null; - /** - * @var PEAR_PackageFile_v2 - */ - var $_packagefile; - /** - * @param PEAR_PackageFile_v2 - */ - function PEAR_PackageFile_Generator_v2(&$packagefile) - { - $this->_packagefile = &$packagefile; - if (isset($this->_packagefile->encoding)) { - $this->_defaultOptions['encoding'] = $this->_packagefile->encoding; - } - } - - /** - * @return string - */ - function getPackagerVersion() - { - return '1.9.0'; - } - - /** - * @param PEAR_Packager - * @param bool generate a .tgz or a .tar - * @param string|null temporary directory to package in - */ - function toTgz(&$packager, $compress = true, $where = null) - { - $a = null; - return $this->toTgz2($packager, $a, $compress, $where); - } - - /** - * Package up both a package.xml and package2.xml for the same release - * @param PEAR_Packager - * @param PEAR_PackageFile_v1 - * @param bool generate a .tgz or a .tar - * @param string|null temporary directory to package in - */ - function toTgz2(&$packager, &$pf1, $compress = true, $where = null) - { - require_once 'Archive/Tar.php'; - if (!$this->_packagefile->isEquivalent($pf1)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . - basename($pf1->getPackageFile()) . - '" is not equivalent to "' . basename($this->_packagefile->getPackageFile()) - . '"'); - } - - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' . - ' not be created'); - } - - $file = $where . DIRECTORY_SEPARATOR . 'package.xml'; - if (file_exists($file) && !is_file($file)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' . - ' "' . $file .'"'); - } - - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml'); - } - - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion(); - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; - if (file_exists($dest_package) && !is_file($dest_package)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' . - $dest_package . '"'); - } - - $pkgfile = $this->_packagefile->getPackageFile(); - if (!$pkgfile) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' . - 'be created from a real file'); - } - - $pkgdir = dirname(realpath($pkgfile)); - $pkgfile = basename($pkgfile); - - // {{{ Create the package file list - $filelist = array(); - $i = 0; - $this->_packagefile->flattenFilelist(); - $contents = $this->_packagefile->getContents(); - if (isset($contents['bundledpackage'])) { // bundles of packages - $contents = $contents['bundledpackage']; - if (!isset($contents[0])) { - $contents = array($contents); - } - - $packageDir = $where; - foreach ($contents as $i => $package) { - $fname = $package; - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return $packager->raiseError("File does not exist: $fname"); - } - - $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; - System::mkdir(array('-p', dirname($tfile))); - copy($file, $tfile); - $filelist[$i++] = $tfile; - $packager->log(2, "Adding package $fname"); - } - } else { // normal packages - $contents = $contents['dir']['file']; - if (!isset($contents[0])) { - $contents = array($contents); - } - - $packageDir = $where; - foreach ($contents as $i => $file) { - $fname = $file['attribs']['name']; - $atts = $file['attribs']; - $orig = $file; - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return $packager->raiseError("File does not exist: $fname"); - } - - $origperms = fileperms($file); - $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; - unset($orig['attribs']); - if (count($orig)) { // file with tasks - // run any package-time tasks - $contents = file_get_contents($file); - foreach ($orig as $tag => $raw) { - $tag = str_replace( - array($this->_packagefile->getTasksNs() . ':', '-'), - array('', '_'), $tag); - $task = "PEAR_Task_$tag"; - $task = &new $task($this->_packagefile->_config, - $this->_packagefile->_logger, - PEAR_TASK_PACKAGE); - $task->init($raw, $atts, null); - $res = $task->startSession($this->_packagefile, $contents, $tfile); - if (!$res) { - continue; // skip this task - } - - if (PEAR::isError($res)) { - return $res; - } - - $contents = $res; // save changes - System::mkdir(array('-p', dirname($tfile))); - $wp = fopen($tfile, "wb"); - fwrite($wp, $contents); - fclose($wp); - } - } - - if (!file_exists($tfile)) { - System::mkdir(array('-p', dirname($tfile))); - copy($file, $tfile); - } - - chmod($tfile, $origperms); - $filelist[$i++] = $tfile; - $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1); - $packager->log(2, "Adding file $fname"); - } - } - // }}} - - $name = $pf1 !== null ? 'package2.xml' : 'package.xml'; - $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name); - if ($packagexml) { - $tar =& new Archive_Tar($dest_package, $compress); - $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors - // ----- Creates with the package.xml file - $ok = $tar->createModify(array($packagexml), '', $where); - if (PEAR::isError($ok)) { - return $packager->raiseError($ok); - } elseif (!$ok) { - return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name . - ' failed'); - } - - // ----- Add the content of the package - if (!$tar->addModify($filelist, $pkgver, $where)) { - return $packager->raiseError( - 'PEAR_Packagefile_v2::toTgz(): tarball creation failed'); - } - - // add the package.xml version 1.0 - if ($pf1 !== null) { - $pfgen = &$pf1->getDefaultGenerator(); - $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); - if (!$tar->addModify(array($packagexml1), '', $where)) { - return $packager->raiseError( - 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed'); - } - } - - return $dest_package; - } - } - - function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml') - { - if (!$this->_packagefile->validate($state)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml', - null, null, null, $this->_packagefile->getValidationWarnings()); - } - - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' . - ' not be created'); - } - - $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; - $np = @fopen($newpkgfile, 'wb'); - if (!$np) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' . - "$name as $newpkgfile"); - } - fwrite($np, $this->toXml($state)); - fclose($np); - return $newpkgfile; - } - - function &toV2() - { - return $this->_packagefile; - } - - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @return string XML data - */ - function toXml($state = PEAR_VALIDATE_NORMAL, $options = array()) - { - $this->_packagefile->setDate(date('Y-m-d')); - $this->_packagefile->setTime(date('H:i:s')); - if (!$this->_packagefile->validate($state)) { - return false; - } - - if (is_array($options)) { - $this->options = array_merge($this->_defaultOptions, $options); - } else { - $this->options = $this->_defaultOptions; - } - - $arr = $this->_packagefile->getArray(); - if (isset($arr['filelist'])) { - unset($arr['filelist']); - } - - if (isset($arr['_lastversion'])) { - unset($arr['_lastversion']); - } - - // Fix the notes a little bit - if (isset($arr['notes'])) { - // This trims out the indenting, needs fixing - $arr['notes'] = "\n" . trim($arr['notes']) . "\n"; - } - - if (isset($arr['changelog']) && !empty($arr['changelog'])) { - // Fix for inconsistency how the array is filled depending on the changelog release amount - if (!isset($arr['changelog']['release'][0])) { - $release = $arr['changelog']['release']; - unset($arr['changelog']['release']); - - $arr['changelog']['release'] = array(); - $arr['changelog']['release'][0] = $release; - } - - foreach (array_keys($arr['changelog']['release']) as $key) { - $c =& $arr['changelog']['release'][$key]; - if (isset($c['notes'])) { - // This trims out the indenting, needs fixing - $c['notes'] = "\n" . trim($c['notes']) . "\n"; - } - } - } - - if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) { - $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']); - unset($arr['contents']['dir']['file']); - if (isset($use['dir'])) { - $arr['contents']['dir']['dir'] = $use['dir']; - } - if (isset($use['file'])) { - $arr['contents']['dir']['file'] = $use['file']; - } - $this->options['beautifyFilelist'] = true; - } - - $arr['attribs']['packagerversion'] = '1.9.0'; - if ($this->serialize($arr, $options)) { - return $this->_serializedData . "\n"; - } - - return false; - } - - - function _recursiveXmlFilelist($list) - { - $dirs = array(); - if (isset($list['attribs'])) { - $file = $list['attribs']['name']; - unset($list['attribs']['name']); - $attributes = $list['attribs']; - $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes); - } else { - foreach ($list as $a) { - $file = $a['attribs']['name']; - $attributes = $a['attribs']; - unset($a['attribs']); - $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a); - } - } - $this->_formatDir($dirs); - $this->_deFormat($dirs); - return $dirs; - } - - function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null) - { - if (!$tasks) { - $tasks = array(); - } - if ($dir == array() || $dir == array('.')) { - $dirs['file'][basename($file)] = $tasks; - $attributes['name'] = basename($file); - $dirs['file'][basename($file)]['attribs'] = $attributes; - return; - } - $curdir = array_shift($dir); - if (!isset($dirs['dir'][$curdir])) { - $dirs['dir'][$curdir] = array(); - } - $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks); - } - - function _formatDir(&$dirs) - { - if (!count($dirs)) { - return array(); - } - $newdirs = array(); - if (isset($dirs['dir'])) { - $newdirs['dir'] = $dirs['dir']; - } - if (isset($dirs['file'])) { - $newdirs['file'] = $dirs['file']; - } - $dirs = $newdirs; - if (isset($dirs['dir'])) { - uksort($dirs['dir'], 'strnatcasecmp'); - foreach ($dirs['dir'] as $dir => $contents) { - $this->_formatDir($dirs['dir'][$dir]); - } - } - if (isset($dirs['file'])) { - uksort($dirs['file'], 'strnatcasecmp'); - }; - } - - function _deFormat(&$dirs) - { - if (!count($dirs)) { - return array(); - } - $newdirs = array(); - if (isset($dirs['dir'])) { - foreach ($dirs['dir'] as $dir => $contents) { - $newdir = array(); - $newdir['attribs']['name'] = $dir; - $this->_deFormat($contents); - foreach ($contents as $tag => $val) { - $newdir[$tag] = $val; - } - $newdirs['dir'][] = $newdir; - } - if (count($newdirs['dir']) == 1) { - $newdirs['dir'] = $newdirs['dir'][0]; - } - } - if (isset($dirs['file'])) { - foreach ($dirs['file'] as $name => $file) { - $newdirs['file'][] = $file; - } - if (count($newdirs['file']) == 1) { - $newdirs['file'] = $newdirs['file'][0]; - } - } - $dirs = $newdirs; - } - - /** - * reset all options to default options - * - * @access public - * @see setOption(), XML_Unserializer() - */ - function resetOptions() - { - $this->options = $this->_defaultOptions; - } - - /** - * set an option - * - * You can use this method if you do not want to set all options in the constructor - * - * @access public - * @see resetOption(), XML_Serializer() - */ - function setOption($name, $value) - { - $this->options[$name] = $value; - } - - /** - * sets several options at once - * - * You can use this method if you do not want to set all options in the constructor - * - * @access public - * @see resetOption(), XML_Unserializer(), setOption() - */ - function setOptions($options) - { - $this->options = array_merge($this->options, $options); - } - - /** - * serialize data - * - * @access public - * @param mixed $data data to serialize - * @return boolean true on success, pear error on failure - */ - function serialize($data, $options = null) - { - // if options have been specified, use them instead - // of the previously defined ones - if (is_array($options)) { - $optionsBak = $this->options; - if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) { - $this->options = array_merge($this->_defaultOptions, $options); - } else { - $this->options = array_merge($this->options, $options); - } - } else { - $optionsBak = null; - } - - // start depth is zero - $this->_tagDepth = 0; - $this->_serializedData = ''; - // serialize an array - if (is_array($data)) { - $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array'; - $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']); - } - - // add doctype declaration - if ($this->options['addDoctype'] === true) { - $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype']) - . $this->options['linebreak'] - . $this->_serializedData; - } - - // build xml declaration - if ($this->options['addDecl']) { - $atts = array(); - $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null; - $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding) - . $this->options['linebreak'] - . $this->_serializedData; - } - - - if ($optionsBak !== null) { - $this->options = $optionsBak; - } - - return true; - } - - /** - * get the result of the serialization - * - * @access public - * @return string serialized XML - */ - function getSerializedData() - { - if ($this->_serializedData === null) { - return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION); - } - return $this->_serializedData; - } - - /** - * serialize any value - * - * This method checks for the type of the value and calls the appropriate method - * - * @access private - * @param mixed $value - * @param string $tagName - * @param array $attributes - * @return string - */ - function _serializeValue($value, $tagName = null, $attributes = array()) - { - if (is_array($value)) { - $xml = $this->_serializeArray($value, $tagName, $attributes); - } elseif (is_object($value)) { - $xml = $this->_serializeObject($value, $tagName); - } else { - $tag = array( - 'qname' => $tagName, - 'attributes' => $attributes, - 'content' => $value - ); - $xml = $this->_createXMLTag($tag); - } - return $xml; - } - - /** - * serialize an array - * - * @access private - * @param array $array array to serialize - * @param string $tagName name of the root tag - * @param array $attributes attributes for the root tag - * @return string $string serialized data - * @uses XML_Util::isValidName() to check, whether key has to be substituted - */ - function _serializeArray(&$array, $tagName = null, $attributes = array()) - { - $_content = null; - - /** - * check for special attributes - */ - if ($this->options['attributesArray'] !== null) { - if (isset($array[$this->options['attributesArray']])) { - $attributes = $array[$this->options['attributesArray']]; - unset($array[$this->options['attributesArray']]); - } - /** - * check for special content - */ - if ($this->options['contentName'] !== null) { - if (isset($array[$this->options['contentName']])) { - $_content = $array[$this->options['contentName']]; - unset($array[$this->options['contentName']]); - } - } - } - - /* - * if mode is set to simpleXML, check whether - * the array is associative or indexed - */ - if (is_array($array) && $this->options['mode'] == 'simplexml') { - $indexed = true; - if (!count($array)) { - $indexed = false; - } - foreach ($array as $key => $val) { - if (!is_int($key)) { - $indexed = false; - break; - } - } - - if ($indexed && $this->options['mode'] == 'simplexml') { - $string = ''; - foreach ($array as $key => $val) { - if ($this->options['beautifyFilelist'] && $tagName == 'dir') { - if (!isset($this->_curdir)) { - $this->_curdir = ''; - } - $savedir = $this->_curdir; - if (isset($val['attribs'])) { - if ($val['attribs']['name'] == '/') { - $this->_curdir = '/'; - } else { - if ($this->_curdir == '/') { - $this->_curdir = ''; - } - $this->_curdir .= '/' . $val['attribs']['name']; - } - } - } - $string .= $this->_serializeValue( $val, $tagName, $attributes); - if ($this->options['beautifyFilelist'] && $tagName == 'dir') { - $string .= ' '; - if (empty($savedir)) { - unset($this->_curdir); - } else { - $this->_curdir = $savedir; - } - } - - $string .= $this->options['linebreak']; - // do indentation - if ($this->options['indent'] !== null && $this->_tagDepth > 0) { - $string .= str_repeat($this->options['indent'], $this->_tagDepth); - } - } - return rtrim($string); - } - } - - if ($this->options['scalarAsAttributes'] === true) { - foreach ($array as $key => $value) { - if (is_scalar($value) && (XML_Util::isValidName($key) === true)) { - unset($array[$key]); - $attributes[$this->options['prependAttributes'].$key] = $value; - } - } - } - - // check for empty array => create empty tag - if (empty($array)) { - $tag = array( - 'qname' => $tagName, - 'content' => $_content, - 'attributes' => $attributes - ); - - } else { - $this->_tagDepth++; - $tmp = $this->options['linebreak']; - foreach ($array as $key => $value) { - // do indentation - if ($this->options['indent'] !== null && $this->_tagDepth > 0) { - $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); - } - - // copy key - $origKey = $key; - // key cannot be used as tagname => use default tag - $valid = XML_Util::isValidName($key); - if (PEAR::isError($valid)) { - if ($this->options['classAsTagName'] && is_object($value)) { - $key = get_class($value); - } else { - $key = $this->options['defaultTagName']; - } - } - $atts = array(); - if ($this->options['typeHints'] === true) { - $atts[$this->options['typeAttribute']] = gettype($value); - if ($key !== $origKey) { - $atts[$this->options['keyAttribute']] = (string)$origKey; - } - - } - if ($this->options['beautifyFilelist'] && $key == 'dir') { - if (!isset($this->_curdir)) { - $this->_curdir = ''; - } - $savedir = $this->_curdir; - if (isset($value['attribs'])) { - if ($value['attribs']['name'] == '/') { - $this->_curdir = '/'; - } else { - $this->_curdir .= '/' . $value['attribs']['name']; - } - } - } - - if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) { - $value .= str_repeat($this->options['indent'], $this->_tagDepth); - } - $tmp .= $this->_createXMLTag(array( - 'qname' => $key, - 'attributes' => $atts, - 'content' => $value ) - ); - if ($this->options['beautifyFilelist'] && $key == 'dir') { - if (isset($value['attribs'])) { - $tmp .= ' '; - if (empty($savedir)) { - unset($this->_curdir); - } else { - $this->_curdir = $savedir; - } - } - } - $tmp .= $this->options['linebreak']; - } - - $this->_tagDepth--; - if ($this->options['indent']!==null && $this->_tagDepth>0) { - $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); - } - - if (trim($tmp) === '') { - $tmp = null; - } - - $tag = array( - 'qname' => $tagName, - 'content' => $tmp, - 'attributes' => $attributes - ); - } - if ($this->options['typeHints'] === true) { - if (!isset($tag['attributes'][$this->options['typeAttribute']])) { - $tag['attributes'][$this->options['typeAttribute']] = 'array'; - } - } - - $string = $this->_createXMLTag($tag, false); - return $string; - } - - /** - * create a tag from an array - * this method awaits an array in the following format - * array( - * 'qname' => $tagName, - * 'attributes' => array(), - * 'content' => $content, // optional - * 'namespace' => $namespace // optional - * 'namespaceUri' => $namespaceUri // optional - * ) - * - * @access private - * @param array $tag tag definition - * @param boolean $replaceEntities whether to replace XML entities in content or not - * @return string $string XML tag - */ - function _createXMLTag($tag, $replaceEntities = true) - { - if ($this->options['indentAttributes'] !== false) { - $multiline = true; - $indent = str_repeat($this->options['indent'], $this->_tagDepth); - - if ($this->options['indentAttributes'] == '_auto') { - $indent .= str_repeat(' ', (strlen($tag['qname'])+2)); - - } else { - $indent .= $this->options['indentAttributes']; - } - } else { - $indent = $multiline = false; - } - - if (is_array($tag['content'])) { - if (empty($tag['content'])) { - $tag['content'] = ''; - } - } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') { - $tag['content'] = ''; - } - - if (is_scalar($tag['content']) || is_null($tag['content'])) { - if ($this->options['encoding'] == 'UTF-8' && - version_compare(phpversion(), '5.0.0', 'lt') - ) { - $tag['content'] = utf8_encode($tag['content']); - } - - if ($replaceEntities === true) { - $replaceEntities = XML_UTIL_ENTITIES_XML; - } - - $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']); - } elseif (is_array($tag['content'])) { - $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']); - } elseif (is_object($tag['content'])) { - $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']); - } elseif (is_resource($tag['content'])) { - settype($tag['content'], 'string'); - $tag = XML_Util::createTagFromArray($tag, $replaceEntities); - } - return $tag; - } -}PEAR-1.9.0/PEAR/PackageFile/Parser/v1.php100664 764 764 40314 100664 12505 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * package.xml abstraction class - */ -require_once 'PEAR/PackageFile/v1.php'; -/** - * Parser for package.xml version 1.0 - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: @PEAR-VER@ - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Parser_v1 -{ - var $_registry; - var $_config; - var $_logger; - /** - * BC hack to allow PEAR_Common::infoFromString() to sort of - * work with the version 2.0 format - there's no filelist though - * @param PEAR_PackageFile_v2 - */ - function fromV2($packagefile) - { - $info = $packagefile->getArray(true); - $ret = new PEAR_PackageFile_v1; - $ret->fromArray($info['old']); - } - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - /** - * @param string contents of package.xml file, version 1.0 - * @return bool success of parsing - */ - function &parse($data, $file, $archive = false) - { - if (!extension_loaded('xml')) { - return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension'); - } - $xp = xml_parser_create(); - if (!$xp) { - $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml'); - return $a; - } - xml_set_object($xp, $this); - xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0'); - xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0'); - xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); - - $this->element_stack = array(); - $this->_packageInfo = array('provides' => array()); - $this->current_element = false; - unset($this->dir_install); - $this->_packageInfo['filelist'] = array(); - $this->filelist =& $this->_packageInfo['filelist']; - $this->dir_names = array(); - $this->in_changelog = false; - $this->d_i = 0; - $this->cdata = ''; - $this->_isValid = true; - - if (!xml_parse($xp, $data, 1)) { - $code = xml_get_error_code($xp); - $line = xml_get_current_line_number($xp); - xml_parser_free($xp); - $a = &PEAR::raiseError(sprintf("XML error: %s at line %d", - $str = xml_error_string($code), $line), 2); - return $a; - } - - xml_parser_free($xp); - - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - if (isset($this->_logger)) { - $pf->setLogger($this->_logger); - } - $pf->setPackagefile($file, $archive); - $pf->fromArray($this->_packageInfo); - return $pf; - } - // {{{ _unIndent() - - /** - * Unindent given string - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } elseif (trim(substr($line, 0, $indent_len))) { - $data .= ltrim($line); - } - } - return $data; - } - - // Support for package DTD v1.0: - // {{{ _element_start_1_0() - - /** - * XML parser callback for ending elements. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name name of ending element - * - * @return void - * - * @access private - */ - function _element_start_1_0($xp, $name, $attribs) - { - array_push($this->element_stack, $name); - $this->current_element = $name; - $spos = sizeof($this->element_stack) - 2; - $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; - $this->current_attributes = $attribs; - $this->cdata = ''; - switch ($name) { - case 'dir': - if ($this->in_changelog) { - break; - } - if (array_key_exists('name', $attribs) && $attribs['name'] != '/') { - $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attribs['name']); - if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) { - $attribs['name'] = substr($attribs['name'], 0, - strlen($attribs['name']) - 1); - } - if (strpos($attribs['name'], '/') === 0) { - $attribs['name'] = substr($attribs['name'], 1); - } - $this->dir_names[] = $attribs['name']; - } - if (isset($attribs['baseinstalldir'])) { - $this->dir_install = $attribs['baseinstalldir']; - } - if (isset($attribs['role'])) { - $this->dir_role = $attribs['role']; - } - break; - case 'file': - if ($this->in_changelog) { - break; - } - if (isset($attribs['name'])) { - $path = ''; - if (count($this->dir_names)) { - foreach ($this->dir_names as $dir) { - $path .= $dir . '/'; - } - } - $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attribs['name']); - unset($attribs['name']); - $this->current_path = $path; - $this->filelist[$path] = $attribs; - // Set the baseinstalldir only if the file don't have this attrib - if (!isset($this->filelist[$path]['baseinstalldir']) && - isset($this->dir_install)) - { - $this->filelist[$path]['baseinstalldir'] = $this->dir_install; - } - // Set the Role - if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { - $this->filelist[$path]['role'] = $this->dir_role; - } - } - break; - case 'replace': - if (!$this->in_changelog) { - $this->filelist[$this->current_path]['replacements'][] = $attribs; - } - break; - case 'maintainers': - $this->_packageInfo['maintainers'] = array(); - $this->m_i = 0; // maintainers array index - break; - case 'maintainer': - // compatibility check - if (!isset($this->_packageInfo['maintainers'])) { - $this->_packageInfo['maintainers'] = array(); - $this->m_i = 0; - } - $this->_packageInfo['maintainers'][$this->m_i] = array(); - $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i]; - break; - case 'changelog': - $this->_packageInfo['changelog'] = array(); - $this->c_i = 0; // changelog array index - $this->in_changelog = true; - break; - case 'release': - if ($this->in_changelog) { - $this->_packageInfo['changelog'][$this->c_i] = array(); - $this->current_release = &$this->_packageInfo['changelog'][$this->c_i]; - } else { - $this->current_release = &$this->_packageInfo; - } - break; - case 'deps': - if (!$this->in_changelog) { - $this->_packageInfo['release_deps'] = array(); - } - break; - case 'dep': - // dependencies array index - if (!$this->in_changelog) { - $this->d_i++; - isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false; - $this->_packageInfo['release_deps'][$this->d_i] = $attribs; - } - break; - case 'configureoptions': - if (!$this->in_changelog) { - $this->_packageInfo['configure_options'] = array(); - } - break; - case 'configureoption': - if (!$this->in_changelog) { - $this->_packageInfo['configure_options'][] = $attribs; - } - break; - case 'provides': - if (empty($attribs['type']) || empty($attribs['name'])) { - break; - } - $attribs['explicit'] = true; - $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs; - break; - case 'package' : - if (isset($attribs['version'])) { - $this->_packageInfo['xsdversion'] = trim($attribs['version']); - } else { - $this->_packageInfo['xsdversion'] = '1.0'; - } - if (isset($attribs['packagerversion'])) { - $this->_packageInfo['packagerversion'] = $attribs['packagerversion']; - } - break; - } - } - - // }}} - // {{{ _element_end_1_0() - - /** - * XML parser callback for ending elements. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name name of ending element - * - * @return void - * - * @access private - */ - function _element_end_1_0($xp, $name) - { - $data = trim($this->cdata); - switch ($name) { - case 'name': - switch ($this->prev_element) { - case 'package': - $this->_packageInfo['package'] = $data; - break; - case 'maintainer': - $this->current_maintainer['name'] = $data; - break; - } - break; - case 'extends' : - $this->_packageInfo['extends'] = $data; - break; - case 'summary': - $this->_packageInfo['summary'] = $data; - break; - case 'description': - $data = $this->_unIndent($this->cdata); - $this->_packageInfo['description'] = $data; - break; - case 'user': - $this->current_maintainer['handle'] = $data; - break; - case 'email': - $this->current_maintainer['email'] = $data; - break; - case 'role': - $this->current_maintainer['role'] = $data; - break; - case 'version': - if ($this->in_changelog) { - $this->current_release['version'] = $data; - } else { - $this->_packageInfo['version'] = $data; - } - break; - case 'date': - if ($this->in_changelog) { - $this->current_release['release_date'] = $data; - } else { - $this->_packageInfo['release_date'] = $data; - } - break; - case 'notes': - // try to "de-indent" release notes in case someone - // has been over-indenting their xml ;-) - // Trim only on the right side - $data = rtrim($this->_unIndent($this->cdata)); - if ($this->in_changelog) { - $this->current_release['release_notes'] = $data; - } else { - $this->_packageInfo['release_notes'] = $data; - } - break; - case 'warnings': - if ($this->in_changelog) { - $this->current_release['release_warnings'] = $data; - } else { - $this->_packageInfo['release_warnings'] = $data; - } - break; - case 'state': - if ($this->in_changelog) { - $this->current_release['release_state'] = $data; - } else { - $this->_packageInfo['release_state'] = $data; - } - break; - case 'license': - if ($this->in_changelog) { - $this->current_release['release_license'] = $data; - } else { - $this->_packageInfo['release_license'] = $data; - } - break; - case 'dep': - if ($data && !$this->in_changelog) { - $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data; - } - break; - case 'dir': - if ($this->in_changelog) { - break; - } - array_pop($this->dir_names); - break; - case 'file': - if ($this->in_changelog) { - break; - } - if ($data) { - $path = ''; - if (count($this->dir_names)) { - foreach ($this->dir_names as $dir) { - $path .= $dir . '/'; - } - } - $path .= $data; - $this->filelist[$path] = $this->current_attributes; - // Set the baseinstalldir only if the file don't have this attrib - if (!isset($this->filelist[$path]['baseinstalldir']) && - isset($this->dir_install)) - { - $this->filelist[$path]['baseinstalldir'] = $this->dir_install; - } - // Set the Role - if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { - $this->filelist[$path]['role'] = $this->dir_role; - } - } - break; - case 'maintainer': - if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) { - $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead'; - } - $this->m_i++; - break; - case 'release': - if ($this->in_changelog) { - $this->c_i++; - } - break; - case 'changelog': - $this->in_changelog = false; - break; - } - array_pop($this->element_stack); - $spos = sizeof($this->element_stack) - 1; - $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : ''; - $this->cdata = ''; - } - - // }}} - // {{{ _pkginfo_cdata_1_0() - - /** - * XML parser callback for character data. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name character data - * - * @return void - * - * @access private - */ - function _pkginfo_cdata_1_0($xp, $data) - { - if (isset($this->cdata)) { - $this->cdata .= $data; - } - } - - // }}} -} -?>PEAR-1.9.0/PEAR/PackageFile/Parser/v2.php100664 764 764 6215 100664 12470 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * base xml parser class - */ -require_once 'PEAR/XMLParser.php'; -require_once 'PEAR/PackageFile/v2.php'; -/** - * Parser for package.xml version 2.0 - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: @PEAR-VER@ - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser -{ - var $_config; - var $_logger; - var $_registry; - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - /** - * Unindent given string - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } else { - $data .= $line . "\n"; - } - } - return $data; - } - - /** - * post-process data - * - * @param string $data - * @param string $element element name - */ - function postProcess($data, $element) - { - if ($element == 'notes') { - return trim($this->_unIndent($data)); - } - return trim($data); - } - - /** - * @param string - * @param string file name of the package.xml - * @param string|false name of the archive this package.xml came from, if any - * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or - * a subclass - * @return PEAR_PackageFile_v2 - */ - function &parse($data, $file, $archive = false, $class = 'PEAR_PackageFile_v2') - { - if (PEAR::isError($err = parent::parse($data, $file))) { - return $err; - } - - $ret = new $class; - $ret->encoding = $this->encoding; - $ret->setConfig($this->_config); - if (isset($this->_logger)) { - $ret->setLogger($this->_logger); - } - - $ret->fromArray($this->_unserializedData); - $ret->setPackagefile($file, $archive); - return $ret; - } -}PEAR-1.9.0/PEAR/PackageFile/v2/rw.php100664 764 764 173210 100664 11724 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a8 - */ -/** - * For base class - */ -require_once 'PEAR/PackageFile/v2.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a8 - */ -class PEAR_PackageFile_v2_rw extends PEAR_PackageFile_v2 -{ - /** - * @param string Extension name - * @return bool success of operation - */ - function setProvidesExtension($extension) - { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - if (!isset($this->_packageInfo['providesextension'])) { - // ensure that the channel tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease', - 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'bundle', 'changelog'), - $extension, 'providesextension'); - } - $this->_packageInfo['providesextension'] = $extension; - return true; - } - return false; - } - - function setPackage($package) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['attribs'])) { - $this->_packageInfo = array_merge(array('attribs' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 - http://pear.php.net/dtd/tasks-1.0.xsd - http://pear.php.net/dtd/package-2.0 - http://pear.php.net/dtd/package-2.0.xsd', - )), $this->_packageInfo); - } - if (!isset($this->_packageInfo['name'])) { - return $this->_packageInfo = array_merge(array('name' => $package), - $this->_packageInfo); - } - $this->_packageInfo['name'] = $package; - } - - /** - * set this as a package.xml version 2.1 - * @access private - */ - function _setPackageVersion2_1() - { - $info = array( - 'version' => '2.1', - 'xmlns' => 'http://pear.php.net/dtd/package-2.1', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 - http://pear.php.net/dtd/tasks-1.0.xsd - http://pear.php.net/dtd/package-2.1 - http://pear.php.net/dtd/package-2.1.xsd', - ); - if (!isset($this->_packageInfo['attribs'])) { - $this->_packageInfo = array_merge(array('attribs' => $info), $this->_packageInfo); - } else { - $this->_packageInfo['attribs'] = $info; - } - } - - function setUri($uri) - { - unset($this->_packageInfo['channel']); - $this->_isValid = 0; - if (!isset($this->_packageInfo['uri'])) { - // ensure that the uri tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('extends', 'summary', 'description', 'lead', - 'developer', 'contributor', 'helper', 'date', 'time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), $uri, 'uri'); - } - $this->_packageInfo['uri'] = $uri; - } - - function setChannel($channel) - { - unset($this->_packageInfo['uri']); - $this->_isValid = 0; - if (!isset($this->_packageInfo['channel'])) { - // ensure that the channel tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('extends', 'summary', 'description', 'lead', - 'developer', 'contributor', 'helper', 'date', 'time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), $channel, 'channel'); - } - $this->_packageInfo['channel'] = $channel; - } - - function setExtends($extends) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['extends'])) { - // ensure that the extends tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('summary', 'description', 'lead', - 'developer', 'contributor', 'helper', 'date', 'time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), $extends, 'extends'); - } - $this->_packageInfo['extends'] = $extends; - } - - function setSummary($summary) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['summary'])) { - // ensure that the summary tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('description', 'lead', - 'developer', 'contributor', 'helper', 'date', 'time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), $summary, 'summary'); - } - $this->_packageInfo['summary'] = $summary; - } - - function setDescription($desc) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['description'])) { - // ensure that the description tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('lead', - 'developer', 'contributor', 'helper', 'date', 'time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), $desc, 'description'); - } - $this->_packageInfo['description'] = $desc; - } - - /** - * Adds a new maintainer - no checking of duplicates is performed, use - * updatemaintainer for that purpose. - */ - function addMaintainer($role, $handle, $name, $email, $active = 'yes') - { - if (!in_array($role, array('lead', 'developer', 'contributor', 'helper'))) { - return false; - } - if (isset($this->_packageInfo[$role])) { - if (!isset($this->_packageInfo[$role][0])) { - $this->_packageInfo[$role] = array($this->_packageInfo[$role]); - } - $this->_packageInfo[$role][] = - array( - 'name' => $name, - 'user' => $handle, - 'email' => $email, - 'active' => $active, - ); - } else { - $testarr = array('lead', - 'developer', 'contributor', 'helper', 'date', 'time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', - 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'); - foreach (array('lead', 'developer', 'contributor', 'helper') as $testrole) { - array_shift($testarr); - if ($role == $testrole) { - break; - } - } - if (!isset($this->_packageInfo[$role])) { - // ensure that the extends tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, $testarr, - array(), $role); - } - $this->_packageInfo[$role] = - array( - 'name' => $name, - 'user' => $handle, - 'email' => $email, - 'active' => $active, - ); - } - $this->_isValid = 0; - } - - function updateMaintainer($newrole, $handle, $name, $email, $active = 'yes') - { - $found = false; - foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { - if (!isset($this->_packageInfo[$role])) { - continue; - } - $info = $this->_packageInfo[$role]; - if (!isset($info[0])) { - if ($info['user'] == $handle) { - $found = true; - break; - } - } - foreach ($info as $i => $maintainer) { - if ($maintainer['user'] == $handle) { - $found = $i; - break 2; - } - } - } - if ($found === false) { - return $this->addMaintainer($newrole, $handle, $name, $email, $active); - } - if ($found !== false) { - if ($found === true) { - unset($this->_packageInfo[$role]); - } else { - unset($this->_packageInfo[$role][$found]); - $this->_packageInfo[$role] = array_values($this->_packageInfo[$role]); - } - } - $this->addMaintainer($newrole, $handle, $name, $email, $active); - $this->_isValid = 0; - } - - function deleteMaintainer($handle) - { - $found = false; - foreach (array('lead', 'developer', 'contributor', 'helper') as $role) { - if (!isset($this->_packageInfo[$role])) { - continue; - } - if (!isset($this->_packageInfo[$role][0])) { - $this->_packageInfo[$role] = array($this->_packageInfo[$role]); - } - foreach ($this->_packageInfo[$role] as $i => $maintainer) { - if ($maintainer['user'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo[$role][$found]); - if (!count($this->_packageInfo[$role]) && $role == 'lead') { - $this->_isValid = 0; - } - if (!count($this->_packageInfo[$role])) { - unset($this->_packageInfo[$role]); - return true; - } - $this->_packageInfo[$role] = - array_values($this->_packageInfo[$role]); - if (count($this->_packageInfo[$role]) == 1) { - $this->_packageInfo[$role] = $this->_packageInfo[$role][0]; - } - return true; - } - if (count($this->_packageInfo[$role]) == 1) { - $this->_packageInfo[$role] = $this->_packageInfo[$role][0]; - } - } - return false; - } - - function setReleaseVersion($version) - { - if (isset($this->_packageInfo['version']) && - isset($this->_packageInfo['version']['release'])) { - unset($this->_packageInfo['version']['release']); - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array( - 'version' => array('stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), - 'release' => array('api'))); - $this->_isValid = 0; - } - - function setAPIVersion($version) - { - if (isset($this->_packageInfo['version']) && - isset($this->_packageInfo['version']['api'])) { - unset($this->_packageInfo['version']['api']); - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array( - 'version' => array('stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), - 'api' => array())); - $this->_isValid = 0; - } - - /** - * snapshot|devel|alpha|beta|stable - */ - function setReleaseStability($state) - { - if (isset($this->_packageInfo['stability']) && - isset($this->_packageInfo['stability']['release'])) { - unset($this->_packageInfo['stability']['release']); - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array( - 'stability' => array('license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), - 'release' => array('api'))); - $this->_isValid = 0; - } - - /** - * @param devel|alpha|beta|stable - */ - function setAPIStability($state) - { - if (isset($this->_packageInfo['stability']) && - isset($this->_packageInfo['stability']['api'])) { - unset($this->_packageInfo['stability']['api']); - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array( - 'stability' => array('license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), - 'api' => array())); - $this->_isValid = 0; - } - - function setLicense($license, $uri = false, $filesource = false) - { - if (!isset($this->_packageInfo['license'])) { - // ensure that the license tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), 0, 'license'); - } - if ($uri || $filesource) { - $attribs = array(); - if ($uri) { - $attribs['uri'] = $uri; - } - $uri = true; // for test below - if ($filesource) { - $attribs['filesource'] = $filesource; - } - } - $license = $uri ? array('attribs' => $attribs, '_content' => $license) : $license; - $this->_packageInfo['license'] = $license; - $this->_isValid = 0; - } - - function setNotes($notes) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['notes'])) { - // ensure that the notes tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('contents', 'compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'extbinrelease', 'bundle', 'changelog'), $notes, 'notes'); - } - $this->_packageInfo['notes'] = $notes; - } - - /** - * This is only used at install-time, after all serialization - * is over. - * @param string file name - * @param string installed path - */ - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - /** - * This is only used at install-time, after all serialization - * is over. - */ - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); - } else { - $this->_packageInfo['filelist'][$file] = $atts['attribs']; - } - } - - /** - * Reset the listing of package contents - * @param string base installation dir for the whole package, if any - */ - function clearContents($baseinstall = false) - { - $this->_filesValid = false; - $this->_isValid = 0; - if (!isset($this->_packageInfo['contents'])) { - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('compatible', - 'dependencies', 'providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', - 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'bundle', 'changelog'), array(), 'contents'); - } - if ($this->getPackageType() != 'bundle') { - $this->_packageInfo['contents'] = - array('dir' => array('attribs' => array('name' => '/'))); - if ($baseinstall) { - $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'] = $baseinstall; - } - } else { - $this->_packageInfo['contents'] = array('bundledpackage' => array()); - } - } - - /** - * @param string relative path of the bundled package. - */ - function addBundledPackage($path) - { - if ($this->getPackageType() != 'bundle') { - return false; - } - $this->_filesValid = false; - $this->_isValid = 0; - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $path, array( - 'contents' => array('compatible', 'dependencies', 'providesextension', - 'usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease', - 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'bundle', 'changelog'), - 'bundledpackage' => array())); - } - - /** - * @param string file name - * @param PEAR_Task_Common a read/write task - */ - function addTaskToFile($filename, $task) - { - if (!method_exists($task, 'getXml')) { - return false; - } - if (!method_exists($task, 'getName')) { - return false; - } - if (!method_exists($task, 'validate')) { - return false; - } - if (!$task->validate()) { - return false; - } - if (!isset($this->_packageInfo['contents']['dir']['file'])) { - return false; - } - $this->getTasksNs(); // discover the tasks namespace if not done already - $files = $this->_packageInfo['contents']['dir']['file']; - if (!isset($files[0])) { - $files = array($files); - $ind = false; - } else { - $ind = true; - } - foreach ($files as $i => $file) { - if (isset($file['attribs'])) { - if ($file['attribs']['name'] == $filename) { - if ($ind) { - $t = isset($this->_packageInfo['contents']['dir']['file'][$i] - ['attribs'][$this->_tasksNs . - ':' . $task->getName()]) ? - $this->_packageInfo['contents']['dir']['file'][$i] - ['attribs'][$this->_tasksNs . - ':' . $task->getName()] : false; - if ($t && !isset($t[0])) { - $this->_packageInfo['contents']['dir']['file'][$i] - [$this->_tasksNs . ':' . $task->getName()] = array($t); - } - $this->_packageInfo['contents']['dir']['file'][$i][$this->_tasksNs . - ':' . $task->getName()][] = $task->getXml(); - } else { - $t = isset($this->_packageInfo['contents']['dir']['file'] - ['attribs'][$this->_tasksNs . - ':' . $task->getName()]) ? $this->_packageInfo['contents']['dir']['file'] - ['attribs'][$this->_tasksNs . - ':' . $task->getName()] : false; - if ($t && !isset($t[0])) { - $this->_packageInfo['contents']['dir']['file'] - [$this->_tasksNs . ':' . $task->getName()] = array($t); - } - $this->_packageInfo['contents']['dir']['file'][$this->_tasksNs . - ':' . $task->getName()][] = $task->getXml(); - } - return true; - } - } - } - return false; - } - - /** - * @param string path to the file - * @param string filename - * @param array extra attributes - */ - function addFile($dir, $file, $attrs) - { - if ($this->getPackageType() == 'bundle') { - return false; - } - $this->_filesValid = false; - $this->_isValid = 0; - $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); - if ($dir == '/' || $dir == '') { - $dir = ''; - } else { - $dir .= '/'; - } - $attrs['name'] = $dir . $file; - if (!isset($this->_packageInfo['contents'])) { - // ensure that the contents tag is set up - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('compatible', 'dependencies', 'providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', - 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'bundle', 'changelog'), array(), 'contents'); - } - if (isset($this->_packageInfo['contents']['dir']['file'])) { - if (!isset($this->_packageInfo['contents']['dir']['file'][0])) { - $this->_packageInfo['contents']['dir']['file'] = - array($this->_packageInfo['contents']['dir']['file']); - } - $this->_packageInfo['contents']['dir']['file'][]['attribs'] = $attrs; - } else { - $this->_packageInfo['contents']['dir']['file']['attribs'] = $attrs; - } - } - - /** - * @param string Dependent package name - * @param string Dependent package's channel name - * @param string minimum version of specified package that this release is guaranteed to be - * compatible with - * @param string maximum version of specified package that this release is guaranteed to be - * compatible with - * @param string versions of specified package that this release is not compatible with - */ - function addCompatiblePackage($name, $channel, $min, $max, $exclude = false) - { - $this->_isValid = 0; - $set = array( - 'name' => $name, - 'channel' => $channel, - 'min' => $min, - 'max' => $max, - ); - if ($exclude) { - $set['exclude'] = $exclude; - } - $this->_isValid = 0; - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array( - 'compatible' => array('dependencies', 'providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog') - )); - } - - /** - * Removes the tag entirely - */ - function resetUsesrole() - { - if (isset($this->_packageInfo['usesrole'])) { - unset($this->_packageInfo['usesrole']); - } - } - - /** - * @param string - * @param string package name or uri - * @param string channel name if non-uri - */ - function addUsesrole($role, $packageOrUri, $channel = false) { - $set = array('role' => $role); - if ($channel) { - $set['package'] = $packageOrUri; - $set['channel'] = $channel; - } else { - $set['uri'] = $packageOrUri; - } - $this->_isValid = 0; - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array( - 'usesrole' => array('usestask', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog') - )); - } - - /** - * Removes the tag entirely - */ - function resetUsestask() - { - if (isset($this->_packageInfo['usestask'])) { - unset($this->_packageInfo['usestask']); - } - } - - - /** - * @param string - * @param string package name or uri - * @param string channel name if non-uri - */ - function addUsestask($task, $packageOrUri, $channel = false) { - $set = array('task' => $task); - if ($channel) { - $set['package'] = $packageOrUri; - $set['channel'] = $channel; - } else { - $set['uri'] = $packageOrUri; - } - $this->_isValid = 0; - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array( - 'usestask' => array('srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog') - )); - } - - /** - * Remove all compatible tags - */ - function clearCompatible() - { - unset($this->_packageInfo['compatible']); - } - - /** - * Reset dependencies prior to adding new ones - */ - function clearDeps() - { - if (!isset($this->_packageInfo['dependencies'])) { - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(), - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'))); - } - $this->_packageInfo['dependencies'] = array(); - } - - /** - * @param string minimum PHP version allowed - * @param string maximum PHP version allowed - * @param array $exclude incompatible PHP versions - */ - function setPhpDep($min, $max = false, $exclude = false) - { - $this->_isValid = 0; - $dep = - array( - 'min' => $min, - ); - if ($max) { - $dep['max'] = $max; - } - if ($exclude) { - if (count($exclude) == 1) { - $exclude = $exclude[0]; - } - $dep['exclude'] = $exclude; - } - if (isset($this->_packageInfo['dependencies']['required']['php'])) { - $this->_stack->push(__FUNCTION__, 'warning', array('dep' => - $this->_packageInfo['dependencies']['required']['php']), - 'warning: PHP dependency already exists, overwriting'); - unset($this->_packageInfo['dependencies']['required']['php']); - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'required' => array('optional', 'group'), - 'php' => array('pearinstaller', 'package', 'subpackage', 'extension', 'os', 'arch') - )); - return true; - } - - /** - * @param string minimum allowed PEAR installer version - * @param string maximum allowed PEAR installer version - * @param string recommended PEAR installer version - * @param array incompatible version of the PEAR installer - */ - function setPearinstallerDep($min, $max = false, $recommended = false, $exclude = false) - { - $this->_isValid = 0; - $dep = - array( - 'min' => $min, - ); - if ($max) { - $dep['max'] = $max; - } - if ($recommended) { - $dep['recommended'] = $recommended; - } - if ($exclude) { - if (count($exclude) == 1) { - $exclude = $exclude[0]; - } - $dep['exclude'] = $exclude; - } - if (isset($this->_packageInfo['dependencies']['required']['pearinstaller'])) { - $this->_stack->push(__FUNCTION__, 'warning', array('dep' => - $this->_packageInfo['dependencies']['required']['pearinstaller']), - 'warning: PEAR Installer dependency already exists, overwriting'); - unset($this->_packageInfo['dependencies']['required']['pearinstaller']); - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'required' => array('optional', 'group'), - 'pearinstaller' => array('package', 'subpackage', 'extension', 'os', 'arch') - )); - } - - /** - * Mark a package as conflicting with this package - * @param string package name - * @param string package channel - * @param string extension this package provides, if any - * @param string|false minimum version required - * @param string|false maximum version allowed - * @param array|false versions to exclude from installation - */ - function addConflictingPackageDepWithChannel($name, $channel, - $providesextension = false, $min = false, $max = false, $exclude = false) - { - $this->_isValid = 0; - $dep = $this->_constructDep($name, $channel, false, $min, $max, false, - $exclude, $providesextension, false, true); - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'required' => array('optional', 'group'), - 'package' => array('subpackage', 'extension', 'os', 'arch') - )); - } - - /** - * Mark a package as conflicting with this package - * @param string package name - * @param string package channel - * @param string extension this package provides, if any - */ - function addConflictingPackageDepWithUri($name, $uri, $providesextension = false) - { - $this->_isValid = 0; - $dep = - array( - 'name' => $name, - 'uri' => $uri, - 'conflicts' => '', - ); - if ($providesextension) { - $dep['providesextension'] = $providesextension; - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'required' => array('optional', 'group'), - 'package' => array('subpackage', 'extension', 'os', 'arch') - )); - } - - function addDependencyGroup($name, $hint) - { - $this->_isValid = 0; - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, - array('attribs' => array('name' => $name, 'hint' => $hint)), - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'group' => array(), - )); - } - - /** - * @param string package name - * @param string|false channel name, false if this is a uri - * @param string|false uri name, false if this is a channel - * @param string|false minimum version required - * @param string|false maximum version allowed - * @param string|false recommended installation version - * @param array|false versions to exclude from installation - * @param string extension this package provides, if any - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - * @param bool if true, tells the installer to negate this dependency (conflicts) - * @return array - * @access private - */ - function _constructDep($name, $channel, $uri, $min, $max, $recommended, $exclude, - $providesextension = false, $nodefault = false, - $conflicts = false) - { - $dep = - array( - 'name' => $name, - ); - if ($channel) { - $dep['channel'] = $channel; - } elseif ($uri) { - $dep['uri'] = $uri; - } - if ($min) { - $dep['min'] = $min; - } - if ($max) { - $dep['max'] = $max; - } - if ($recommended) { - $dep['recommended'] = $recommended; - } - if ($exclude) { - if (is_array($exclude) && count($exclude) == 1) { - $exclude = $exclude[0]; - } - $dep['exclude'] = $exclude; - } - if ($conflicts) { - $dep['conflicts'] = ''; - } - if ($nodefault) { - $dep['nodefault'] = ''; - } - if ($providesextension) { - $dep['providesextension'] = $providesextension; - } - return $dep; - } - - /** - * @param package|subpackage - * @param string group name - * @param string package name - * @param string package channel - * @param string minimum version - * @param string maximum version - * @param string recommended version - * @param array|false optional excluded versions - * @param string extension this package provides, if any - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - * @return bool false if the dependency group has not been initialized with - * {@link addDependencyGroup()}, or a subpackage is added with - * a providesextension - */ - function addGroupPackageDepWithChannel($type, $groupname, $name, $channel, $min = false, - $max = false, $recommended = false, $exclude = false, - $providesextension = false, $nodefault = false) - { - if ($type == 'subpackage' && $providesextension) { - return false; // subpackages must be php packages - } - $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude, - $providesextension, $nodefault); - return $this->_addGroupDependency($type, $dep, $groupname); - } - - /** - * @param package|subpackage - * @param string group name - * @param string package name - * @param string package uri - * @param string extension this package provides, if any - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - * @return bool false if the dependency group has not been initialized with - * {@link addDependencyGroup()} - */ - function addGroupPackageDepWithURI($type, $groupname, $name, $uri, $providesextension = false, - $nodefault = false) - { - if ($type == 'subpackage' && $providesextension) { - return false; // subpackages must be php packages - } - $dep = $this->_constructDep($name, false, $uri, false, false, false, false, - $providesextension, $nodefault); - return $this->_addGroupDependency($type, $dep, $groupname); - } - - /** - * @param string group name (must be pre-existing) - * @param string extension name - * @param string minimum version allowed - * @param string maximum version allowed - * @param string recommended version - * @param array incompatible versions - */ - function addGroupExtensionDep($groupname, $name, $min = false, $max = false, - $recommended = false, $exclude = false) - { - $this->_isValid = 0; - $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude); - return $this->_addGroupDependency('extension', $dep, $groupname); - } - - /** - * @param package|subpackage|extension - * @param array dependency contents - * @param string name of the dependency group to add this to - * @return boolean - * @access private - */ - function _addGroupDependency($type, $dep, $groupname) - { - $arr = array('subpackage', 'extension'); - if ($type != 'package') { - array_shift($arr); - } - if ($type == 'extension') { - array_shift($arr); - } - if (!isset($this->_packageInfo['dependencies']['group'])) { - return false; - } else { - if (!isset($this->_packageInfo['dependencies']['group'][0])) { - if ($this->_packageInfo['dependencies']['group']['attribs']['name'] == $groupname) { - $this->_packageInfo['dependencies']['group'] = $this->_mergeTag( - $this->_packageInfo['dependencies']['group'], $dep, - array( - $type => $arr - )); - $this->_isValid = 0; - return true; - } else { - return false; - } - } else { - foreach ($this->_packageInfo['dependencies']['group'] as $i => $group) { - if ($group['attribs']['name'] == $groupname) { - $this->_packageInfo['dependencies']['group'][$i] = $this->_mergeTag( - $this->_packageInfo['dependencies']['group'][$i], $dep, - array( - $type => $arr - )); - $this->_isValid = 0; - return true; - } - } - return false; - } - } - } - - /** - * @param optional|required - * @param string package name - * @param string package channel - * @param string minimum version - * @param string maximum version - * @param string recommended version - * @param string extension this package provides, if any - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - * @param array|false optional excluded versions - */ - function addPackageDepWithChannel($type, $name, $channel, $min = false, $max = false, - $recommended = false, $exclude = false, - $providesextension = false, $nodefault = false) - { - if (!in_array($type, array('optional', 'required'), true)) { - $type = 'required'; - } - $this->_isValid = 0; - $arr = array('optional', 'group'); - if ($type != 'required') { - array_shift($arr); - } - $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude, - $providesextension, $nodefault); - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - $type => $arr, - 'package' => array('subpackage', 'extension', 'os', 'arch') - )); - } - - /** - * @param optional|required - * @param string name of the package - * @param string uri of the package - * @param string extension this package provides, if any - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - */ - function addPackageDepWithUri($type, $name, $uri, $providesextension = false, - $nodefault = false) - { - $this->_isValid = 0; - $arr = array('optional', 'group'); - if ($type != 'required') { - array_shift($arr); - } - $dep = $this->_constructDep($name, false, $uri, false, false, false, false, - $providesextension, $nodefault); - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - $type => $arr, - 'package' => array('subpackage', 'extension', 'os', 'arch') - )); - } - - /** - * @param optional|required optional, required - * @param string package name - * @param string package channel - * @param string minimum version - * @param string maximum version - * @param string recommended version - * @param array incompatible versions - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - */ - function addSubpackageDepWithChannel($type, $name, $channel, $min = false, $max = false, - $recommended = false, $exclude = false, - $nodefault = false) - { - $this->_isValid = 0; - $arr = array('optional', 'group'); - if ($type != 'required') { - array_shift($arr); - } - $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude, - $nodefault); - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - $type => $arr, - 'subpackage' => array('extension', 'os', 'arch') - )); - } - - /** - * @param optional|required optional, required - * @param string package name - * @param string package uri for download - * @param bool if true, tells the installer to ignore the default optional dependency group - * when installing this package - */ - function addSubpackageDepWithUri($type, $name, $uri, $nodefault = false) - { - $this->_isValid = 0; - $arr = array('optional', 'group'); - if ($type != 'required') { - array_shift($arr); - } - $dep = $this->_constructDep($name, false, $uri, false, false, false, false, $nodefault); - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - $type => $arr, - 'subpackage' => array('extension', 'os', 'arch') - )); - } - - /** - * @param optional|required optional, required - * @param string extension name - * @param string minimum version - * @param string maximum version - * @param string recommended version - * @param array incompatible versions - */ - function addExtensionDep($type, $name, $min = false, $max = false, $recommended = false, - $exclude = false) - { - $this->_isValid = 0; - $arr = array('optional', 'group'); - if ($type != 'required') { - array_shift($arr); - } - $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude); - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - $type => $arr, - 'extension' => array('os', 'arch') - )); - } - - /** - * @param string Operating system name - * @param boolean true if this package cannot be installed on this OS - */ - function addOsDep($name, $conflicts = false) - { - $this->_isValid = 0; - $dep = array('name' => $name); - if ($conflicts) { - $dep['conflicts'] = ''; - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'required' => array('optional', 'group'), - 'os' => array('arch') - )); - } - - /** - * @param string Architecture matching pattern - * @param boolean true if this package cannot be installed on this architecture - */ - function addArchDep($pattern, $conflicts = false) - { - $this->_isValid = 0; - $dep = array('pattern' => $pattern); - if ($conflicts) { - $dep['conflicts'] = ''; - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep, - array( - 'dependencies' => array('providesextension', 'usesrole', 'usestask', - 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'), - 'required' => array('optional', 'group'), - 'arch' => array() - )); - } - - /** - * Set the kind of package, and erase all release tags - * - * - a php package is a PEAR-style package - * - an extbin package is a PECL-style extension binary - * - an extsrc package is a PECL-style source for a binary - * - an zendextbin package is a PECL-style zend extension binary - * - an zendextsrc package is a PECL-style source for a zend extension binary - * - a bundle package is a collection of other pre-packaged packages - * @param php|extbin|extsrc|zendextsrc|zendextbin|bundle - * @return bool success - */ - function setPackageType($type) - { - $this->_isValid = 0; - if (!in_array($type, array('php', 'extbin', 'extsrc', 'zendextsrc', - 'zendextbin', 'bundle'))) { - return false; - } - - if (in_array($type, array('zendextsrc', 'zendextbin'))) { - $this->_setPackageVersion2_1(); - } - - if ($type != 'bundle') { - $type .= 'release'; - } - - foreach (array('phprelease', 'extbinrelease', 'extsrcrelease', - 'zendextsrcrelease', 'zendextbinrelease', 'bundle') as $test) { - unset($this->_packageInfo[$test]); - } - - if (!isset($this->_packageInfo[$type])) { - // ensure that the release tag is set up - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('changelog'), - array(), $type); - } - - $this->_packageInfo[$type] = array(); - return true; - } - - /** - * @return bool true if package type is set up - */ - function addRelease() - { - if ($type = $this->getPackageType()) { - if ($type != 'bundle') { - $type .= 'release'; - } - $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(), - array($type => array('changelog'))); - return true; - } - return false; - } - - /** - * Get the current release tag in order to add to it - * @param bool returns only releases that have installcondition if true - * @return array|null - */ - function &_getCurrentRelease($strict = true) - { - if ($p = $this->getPackageType()) { - if ($strict) { - if ($p == 'extsrc' || $p == 'zendextsrc') { - $a = null; - return $a; - } - } - if ($p != 'bundle') { - $p .= 'release'; - } - if (isset($this->_packageInfo[$p][0])) { - return $this->_packageInfo[$p][count($this->_packageInfo[$p]) - 1]; - } else { - return $this->_packageInfo[$p]; - } - } else { - $a = null; - return $a; - } - } - - /** - * Add a file to the current release that should be installed under a different name - * @param string path to file - * @param string name the file should be installed as - */ - function addInstallAs($path, $as) - { - $r = &$this->_getCurrentRelease(); - if ($r === null) { - return false; - } - $this->_isValid = 0; - $r = $this->_mergeTag($r, array('attribs' => array('name' => $path, 'as' => $as)), - array( - 'filelist' => array(), - 'install' => array('ignore') - )); - } - - /** - * Add a file to the current release that should be ignored - * @param string path to file - * @return bool success of operation - */ - function addIgnore($path) - { - $r = &$this->_getCurrentRelease(); - if ($r === null) { - return false; - } - $this->_isValid = 0; - $r = $this->_mergeTag($r, array('attribs' => array('name' => $path)), - array( - 'filelist' => array(), - 'ignore' => array() - )); - } - - /** - * Add an extension binary package for this extension source code release - * - * Note that the package must be from the same channel as the extension source package - * @param string - */ - function addBinarypackage($package) - { - if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { - return false; - } - $r = &$this->_getCurrentRelease(false); - if ($r === null) { - return false; - } - $this->_isValid = 0; - $r = $this->_mergeTag($r, $package, - array( - 'binarypackage' => array('filelist'), - )); - } - - /** - * Add a configureoption to an extension source package - * @param string - * @param string - * @param string - */ - function addConfigureOption($name, $prompt, $default = null) - { - if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { - return false; - } - - $r = &$this->_getCurrentRelease(false); - if ($r === null) { - return false; - } - - $opt = array('attribs' => array('name' => $name, 'prompt' => $prompt)); - if ($default !== null) { - $opt['attribs']['default'] = $default; - } - - $this->_isValid = 0; - $r = $this->_mergeTag($r, $opt, - array( - 'configureoption' => array('binarypackage', 'filelist'), - )); - } - - /** - * Set an installation condition based on php version for the current release set - * @param string minimum version - * @param string maximum version - * @param false|array incompatible versions of PHP - */ - function setPhpInstallCondition($min, $max, $exclude = false) - { - $r = &$this->_getCurrentRelease(); - if ($r === null) { - return false; - } - $this->_isValid = 0; - if (isset($r['installconditions']['php'])) { - unset($r['installconditions']['php']); - } - $dep = array('min' => $min, 'max' => $max); - if ($exclude) { - if (is_array($exclude) && count($exclude) == 1) { - $exclude = $exclude[0]; - } - $dep['exclude'] = $exclude; - } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('configureoption', 'binarypackage', - 'filelist'), - 'php' => array('extension', 'os', 'arch') - )); - } else { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('filelist'), - 'php' => array('extension', 'os', 'arch') - )); - } - } - - /** - * @param optional|required optional, required - * @param string extension name - * @param string minimum version - * @param string maximum version - * @param string recommended version - * @param array incompatible versions - */ - function addExtensionInstallCondition($name, $min = false, $max = false, $recommended = false, - $exclude = false) - { - $r = &$this->_getCurrentRelease(); - if ($r === null) { - return false; - } - $this->_isValid = 0; - $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude); - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('configureoption', 'binarypackage', - 'filelist'), - 'extension' => array('os', 'arch') - )); - } else { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('filelist'), - 'extension' => array('os', 'arch') - )); - } - } - - /** - * Set an installation condition based on operating system for the current release set - * @param string OS name - * @param bool whether this OS is incompatible with the current release - */ - function setOsInstallCondition($name, $conflicts = false) - { - $r = &$this->_getCurrentRelease(); - if ($r === null) { - return false; - } - $this->_isValid = 0; - if (isset($r['installconditions']['os'])) { - unset($r['installconditions']['os']); - } - $dep = array('name' => $name); - if ($conflicts) { - $dep['conflicts'] = ''; - } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('configureoption', 'binarypackage', - 'filelist'), - 'os' => array('arch') - )); - } else { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('filelist'), - 'os' => array('arch') - )); - } - } - - /** - * Set an installation condition based on architecture for the current release set - * @param string architecture pattern - * @param bool whether this arch is incompatible with the current release - */ - function setArchInstallCondition($pattern, $conflicts = false) - { - $r = &$this->_getCurrentRelease(); - if ($r === null) { - return false; - } - $this->_isValid = 0; - if (isset($r['installconditions']['arch'])) { - unset($r['installconditions']['arch']); - } - $dep = array('pattern' => $pattern); - if ($conflicts) { - $dep['conflicts'] = ''; - } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('configureoption', 'binarypackage', - 'filelist'), - 'arch' => array() - )); - } else { - $r = $this->_mergeTag($r, $dep, - array( - 'installconditions' => array('filelist'), - 'arch' => array() - )); - } - } - - /** - * For extension binary releases, this is used to specify either the - * static URI to a source package, or the package name and channel of the extsrc/zendextsrc - * package it is based on. - * @param string Package name, or full URI to source package (extsrc/zendextsrc type) - */ - function setSourcePackage($packageOrUri) - { - $this->_isValid = 0; - if (isset($this->_packageInfo['channel'])) { - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease', - 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'bundle', 'changelog'), - $packageOrUri, 'srcpackage'); - } else { - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease', - 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', - 'bundle', 'changelog'), $packageOrUri, 'srcuri'); - } - } - - /** - * Generate a valid change log entry from the current package.xml - * @param string|false - */ - function generateChangeLogEntry($notes = false) - { - return array( - 'version' => - array( - 'release' => $this->getVersion('release'), - 'api' => $this->getVersion('api'), - ), - 'stability' => - $this->getStability(), - 'date' => $this->getDate(), - 'license' => $this->getLicense(true), - 'notes' => $notes ? $notes : $this->getNotes() - ); - } - - /** - * @param string release version to set change log notes for - * @param array output of {@link generateChangeLogEntry()} - */ - function setChangelogEntry($releaseversion, $contents) - { - if (!isset($this->_packageInfo['changelog'])) { - $this->_packageInfo['changelog']['release'] = $contents; - return; - } - if (!isset($this->_packageInfo['changelog']['release'][0])) { - if ($this->_packageInfo['changelog']['release']['version']['release'] == $releaseversion) { - $this->_packageInfo['changelog']['release'] = array( - $this->_packageInfo['changelog']['release']); - } else { - $this->_packageInfo['changelog']['release'] = array( - $this->_packageInfo['changelog']['release']); - return $this->_packageInfo['changelog']['release'][] = $contents; - } - } - foreach($this->_packageInfo['changelog']['release'] as $index => $changelog) { - if (isset($changelog['version']) && - strnatcasecmp($changelog['version']['release'], $releaseversion) == 0) { - $curlog = $index; - } - } - if (isset($curlog)) { - $this->_packageInfo['changelog']['release'][$curlog] = $contents; - } else { - $this->_packageInfo['changelog']['release'][] = $contents; - } - } - - /** - * Remove the changelog entirely - */ - function clearChangeLog() - { - unset($this->_packageInfo['changelog']); - } -}PEAR-1.9.0/PEAR/PackageFile/v2/Validator.php100664 764 764 250041 100664 13217 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validator.php 277885 2009-03-27 19:29:31Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a8 - */ -/** - * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its - * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a8 - * @access private - */ -class PEAR_PackageFile_v2_Validator -{ - /** - * @var array - */ - var $_packageInfo; - /** - * @var PEAR_PackageFile_v2 - */ - var $_pf; - /** - * @var PEAR_ErrorStack - */ - var $_stack; - /** - * @var int - */ - var $_isValid = 0; - /** - * @var int - */ - var $_filesValid = 0; - /** - * @var int - */ - var $_curState = 0; - /** - * @param PEAR_PackageFile_v2 - * @param int - */ - function validate(&$pf, $state = PEAR_VALIDATE_NORMAL) - { - $this->_pf = &$pf; - $this->_curState = $state; - $this->_packageInfo = $this->_pf->getArray(); - $this->_isValid = $this->_pf->_isValid; - $this->_filesValid = $this->_pf->_filesValid; - $this->_stack = &$pf->_stack; - $this->_stack->getErrors(true); - if (($this->_isValid & $state) == $state) { - return true; - } - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { - return false; - } - if (!isset($this->_packageInfo['attribs']['version']) || - ($this->_packageInfo['attribs']['version'] != '2.0' && - $this->_packageInfo['attribs']['version'] != '2.1') - ) { - $this->_noPackageVersion(); - } - $structure = - array( - 'name', - 'channel|uri', - '*extends', // can't be multiple, but this works fine - 'summary', - 'description', - '+lead', // these all need content checks - '*developer', - '*contributor', - '*helper', - 'date', - '*time', - 'version', - 'stability', - 'license->?uri->?filesource', - 'notes', - 'contents', //special validation needed - '*compatible', - 'dependencies', //special validation needed - '*usesrole', - '*usestask', // reserve these for 1.4.0a1 to implement - // this will allow a package.xml to gracefully say it - // needs a certain package installed in order to implement a role or task - '*providesextension', - '*srcpackage|*srcuri', - '+phprelease|+extsrcrelease|+extbinrelease|' . - '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed - '*changelog', - ); - $test = $this->_packageInfo; - if (isset($test['dependencies']) && - isset($test['dependencies']['required']) && - isset($test['dependencies']['required']['pearinstaller']) && - isset($test['dependencies']['required']['pearinstaller']['min']) && - version_compare('1.9.0', - $test['dependencies']['required']['pearinstaller']['min'], '<') - ) { - $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']); - return false; - } - // ignore post-installation array fields - if (array_key_exists('filelist', $test)) { - unset($test['filelist']); - } - if (array_key_exists('_lastmodified', $test)) { - unset($test['_lastmodified']); - } - if (array_key_exists('#binarypackage', $test)) { - unset($test['#binarypackage']); - } - if (array_key_exists('old', $test)) { - unset($test['old']); - } - if (array_key_exists('_lastversion', $test)) { - unset($test['_lastversion']); - } - if (!$this->_stupidSchemaValidate($structure, $test, '')) { - return false; - } - if (empty($this->_packageInfo['name'])) { - $this->_tagCannotBeEmpty('name'); - } - $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel'; - if (empty($this->_packageInfo[$test])) { - $this->_tagCannotBeEmpty($test); - } - if (is_array($this->_packageInfo['license']) && - (!isset($this->_packageInfo['license']['_content']) || - empty($this->_packageInfo['license']['_content']))) { - $this->_tagCannotBeEmpty('license'); - } elseif (empty($this->_packageInfo['license'])) { - $this->_tagCannotBeEmpty('license'); - } - if (empty($this->_packageInfo['summary'])) { - $this->_tagCannotBeEmpty('summary'); - } - if (empty($this->_packageInfo['description'])) { - $this->_tagCannotBeEmpty('description'); - } - if (empty($this->_packageInfo['date'])) { - $this->_tagCannotBeEmpty('date'); - } - if (empty($this->_packageInfo['notes'])) { - $this->_tagCannotBeEmpty('notes'); - } - if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) { - $this->_tagCannotBeEmpty('time'); - } - if (isset($this->_packageInfo['dependencies'])) { - $this->_validateDependencies(); - } - if (isset($this->_packageInfo['compatible'])) { - $this->_validateCompatible(); - } - if (!isset($this->_packageInfo['bundle'])) { - if (empty($this->_packageInfo['contents'])) { - $this->_tagCannotBeEmpty('contents'); - } - if (!isset($this->_packageInfo['contents']['dir'])) { - $this->_filelistMustContainDir('contents'); - return false; - } - if (isset($this->_packageInfo['contents']['file'])) { - $this->_filelistCannotContainFile('contents'); - return false; - } - } - $this->_validateMaintainers(); - $this->_validateStabilityVersion(); - $fail = false; - if (array_key_exists('usesrole', $this->_packageInfo)) { - $roles = $this->_packageInfo['usesrole']; - if (!is_array($roles) || !isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if (!isset($role['role'])) { - $this->_usesroletaskMustHaveRoleTask('usesrole', 'role'); - $fail = true; - } else { - if (!isset($role['channel'])) { - if (!isset($role['uri'])) { - $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole'); - $fail = true; - } - } elseif (!isset($role['package'])) { - $this->_usesroletaskMustHavePackage($role['role'], 'usesrole'); - $fail = true; - } - } - } - } - if (array_key_exists('usestask', $this->_packageInfo)) { - $roles = $this->_packageInfo['usestask']; - if (!is_array($roles) || !isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if (!isset($role['task'])) { - $this->_usesroletaskMustHaveRoleTask('usestask', 'task'); - $fail = true; - } else { - if (!isset($role['channel'])) { - if (!isset($role['uri'])) { - $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask'); - $fail = true; - } - } elseif (!isset($role['package'])) { - $this->_usesroletaskMustHavePackage($role['task'], 'usestask'); - $fail = true; - } - } - } - } - - if ($fail) { - return false; - } - - $list = $this->_packageInfo['contents']; - if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) { - $this->_multipleToplevelDirNotAllowed(); - return $this->_isValid = 0; - } - - $this->_validateFilelist(); - $this->_validateRelease(); - if (!$this->_stack->hasErrors()) { - $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true); - if (PEAR::isError($chan)) { - $this->_unknownChannel($this->_pf->getChannel()); - } else { - $valpack = $chan->getValidationPackage(); - // for channel validator packages, always use the default PEAR validator. - // otherwise, they can't be installed or packaged - $validator = $chan->getValidationObject($this->_pf->getPackage()); - if (!$validator) { - $this->_stack->push(__FUNCTION__, 'error', - array_merge( - array('channel' => $chan->getName(), - 'package' => $this->_pf->getPackage()), - $valpack - ), - 'package "%channel%/%package%" cannot be properly validated without ' . - 'validation package "%channel%/%name%-%version%"'); - return $this->_isValid = 0; - } - $validator->setPackageFile($this->_pf); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_stack->push(__FUNCTION__, 'error', $error, - 'Channel validator error: field "%field%" - %reason%'); - } - foreach ($failures['warnings'] as $warning) { - $this->_stack->push(__FUNCTION__, 'warning', $warning, - 'Channel validator warning: field "%field%" - %reason%'); - } - } - } - - $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error'); - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) { - if ($this->_pf->getPackageType() == 'bundle') { - if ($this->_analyzeBundledPackages()) { - $this->_filesValid = $this->_pf->_filesValid = true; - } else { - $this->_pf->_isValid = $this->_isValid = 0; - } - } else { - if (!$this->_analyzePhpFiles()) { - $this->_pf->_isValid = $this->_isValid = 0; - } else { - $this->_filesValid = $this->_pf->_filesValid = true; - } - } - } - - if ($this->_isValid) { - return $this->_pf->_isValid = $this->_isValid = $state; - } - - return $this->_pf->_isValid = $this->_isValid = 0; - } - - function _stupidSchemaValidate($structure, $xml, $root) - { - if (!is_array($xml)) { - $xml = array(); - } - $keys = array_keys($xml); - reset($keys); - $key = current($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - $unfoundtags = $optionaltags = array(); - $ret = true; - $mismatch = false; - foreach ($structure as $struc) { - if ($key) { - $tag = $xml[$key]; - } - $test = $this->_processStructure($struc); - if (isset($test['choices'])) { - $loose = true; - foreach ($test['choices'] as $choice) { - if ($key == $choice['tag']) { - $key = next($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - $unfoundtags = $optionaltags = array(); - $mismatch = false; - if ($key && $key != $choice['tag'] && isset($choice['multiple'])) { - $unfoundtags[] = $choice['tag']; - $optionaltags[] = $choice['tag']; - if ($key) { - $mismatch = true; - } - } - $ret &= $this->_processAttribs($choice, $tag, $root); - continue 2; - } else { - $unfoundtags[] = $choice['tag']; - $mismatch = true; - } - if (!isset($choice['multiple']) || $choice['multiple'] != '*') { - $loose = false; - } else { - $optionaltags[] = $choice['tag']; - } - } - if (!$loose) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } - } else { - if ($key != $test['tag']) { - if (isset($test['multiple']) && $test['multiple'] != '*') { - $unfoundtags[] = $test['tag']; - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } else { - if ($key) { - $mismatch = true; - } - $unfoundtags[] = $test['tag']; - $optionaltags[] = $test['tag']; - } - if (!isset($test['multiple'])) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } - continue; - } else { - $unfoundtags = $optionaltags = array(); - $mismatch = false; - } - $key = next($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - if ($key && $key != $test['tag'] && isset($test['multiple'])) { - $unfoundtags[] = $test['tag']; - $optionaltags[] = $test['tag']; - $mismatch = true; - } - $ret &= $this->_processAttribs($test, $tag, $root); - continue; - } - } - if (!$mismatch && count($optionaltags)) { - // don't error out on any optional tags - $unfoundtags = array_diff($unfoundtags, $optionaltags); - } - if (count($unfoundtags)) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - } elseif ($key) { - // unknown tags - $this->_invalidTagOrder('*no tags allowed here*', $key, $root); - while ($key = next($keys)) { - $this->_invalidTagOrder('*no tags allowed here*', $key, $root); - } - } - return $ret; - } - - function _processAttribs($choice, $tag, $context) - { - if (isset($choice['attribs'])) { - if (!is_array($tag)) { - $tag = array($tag); - } - $tags = $tag; - if (!isset($tags[0])) { - $tags = array($tags); - } - $ret = true; - foreach ($tags as $i => $tag) { - if (!is_array($tag) || !isset($tag['attribs'])) { - foreach ($choice['attribs'] as $attrib) { - if ($attrib{0} != '?') { - $ret &= $this->_tagHasNoAttribs($choice['tag'], - $context); - continue 2; - } - } - } - foreach ($choice['attribs'] as $attrib) { - if ($attrib{0} != '?') { - if (!isset($tag['attribs'][$attrib])) { - $ret &= $this->_tagMissingAttribute($choice['tag'], - $attrib, $context); - } - } - } - } - return $ret; - } - return true; - } - - function _processStructure($key) - { - $ret = array(); - if (count($pieces = explode('|', $key)) > 1) { - $ret['choices'] = array(); - foreach ($pieces as $piece) { - $ret['choices'][] = $this->_processStructure($piece); - } - return $ret; - } - $multi = $key{0}; - if ($multi == '+' || $multi == '*') { - $ret['multiple'] = $key{0}; - $key = substr($key, 1); - } - if (count($attrs = explode('->', $key)) > 1) { - $ret['tag'] = array_shift($attrs); - $ret['attribs'] = $attrs; - } else { - $ret['tag'] = $key; - } - return $ret; - } - - function _validateStabilityVersion() - { - $structure = array('release', 'api'); - $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], ''); - $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], ''); - if ($a) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $this->_packageInfo['version']['release'])) { - $this->_invalidVersion('release', $this->_packageInfo['version']['release']); - } - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $this->_packageInfo['version']['api'])) { - $this->_invalidVersion('api', $this->_packageInfo['version']['api']); - } - if (!in_array($this->_packageInfo['stability']['release'], - array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) { - $this->_invalidState('release', $this->_packageInfo['stability']['release']); - } - if (!in_array($this->_packageInfo['stability']['api'], - array('devel', 'alpha', 'beta', 'stable'))) { - $this->_invalidState('api', $this->_packageInfo['stability']['api']); - } - } - } - - function _validateMaintainers() - { - $structure = - array( - 'name', - 'user', - 'email', - 'active', - ); - foreach (array('lead', 'developer', 'contributor', 'helper') as $type) { - if (!isset($this->_packageInfo[$type])) { - continue; - } - if (isset($this->_packageInfo[$type][0])) { - foreach ($this->_packageInfo[$type] as $lead) { - $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>'); - } - } else { - $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type], - '<' . $type . '>'); - } - } - } - - function _validatePhpDep($dep, $installcondition = false) - { - $structure = array( - 'min', - '*max', - '*exclude', - ); - $type = $installcondition ? '' : ''; - $this->_stupidSchemaValidate($structure, $dep, $type); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $dep['min'])) { - $this->_invalidVersion($type . '', $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $dep['max'])) { - $this->_invalidVersion($type . '', $dep['max']); - } - } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match( - '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $exclude)) { - $this->_invalidVersion($type . '', $exclude); - } - } - } - } - - function _validatePearinstallerDep($dep) - { - $structure = array( - 'min', - '*max', - '*recommended', - '*exclude', - ); - $this->_stupidSchemaValidate($structure, $dep, ''); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion('', - $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['max'])) { - $this->_invalidVersion('', - $dep['max']); - } - } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion('', - $dep['recommended']); - } - } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion('', - $exclude); - } - } - } - } - - function _validatePackageDep($dep, $group, $type = '') - { - if (isset($dep['uri'])) { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - 'uri', - 'conflicts', - '*providesextension', - ); - } else { - $structure = array( - 'name', - 'uri', - '*providesextension', - ); - } - } else { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - 'channel', - '*min', - '*max', - '*exclude', - 'conflicts', - '*providesextension', - ); - } else { - $structure = array( - 'name', - 'channel', - '*min', - '*max', - '*recommended', - '*exclude', - '*nodefault', - '*providesextension', - ); - } - } - if (isset($dep['name'])) { - $type .= '' . $dep['name'] . ''; - } - $this->_stupidSchemaValidate($structure, $dep, '' . $group . $type); - if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || - isset($dep['recommended']) || isset($dep['exclude']))) { - $this->_uriDepsCannotHaveVersioning('' . $group . $type); - } - if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') { - $this->_DepchannelCannotBeUri('' . $group . $type); - } - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion('' . $group . $type . '', $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['max'])) { - $this->_invalidVersion('' . $group . $type . '', $dep['max']); - } - } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion('' . $group . $type . '', - $dep['recommended']); - } - } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion('' . $group . $type . '', - $exclude); - } - } - } - } - - function _validateSubpackageDep($dep, $group) - { - $this->_validatePackageDep($dep, $group, ''); - if (isset($dep['providesextension'])) { - $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : ''); - } - if (isset($dep['conflicts'])) { - $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : ''); - } - } - - function _validateExtensionDep($dep, $group = false, $installcondition = false) - { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - '*min', - '*max', - '*exclude', - 'conflicts', - ); - } else { - $structure = array( - 'name', - '*min', - '*max', - '*recommended', - '*exclude', - ); - } - if ($installcondition) { - $type = ''; - } else { - $type = '' . $group . ''; - } - if (isset($dep['name'])) { - $type .= '' . $dep['name'] . ''; - } - $this->_stupidSchemaValidate($structure, $dep, $type); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '' : ''; - if ($this->_stupidSchemaValidate($structure, $dep, $type)) { - if ($dep['name'] == '*') { - if (array_key_exists('conflicts', $dep)) { - $this->_cannotConflictWithAllOs($type); - } - } - } - } - - function _validateArchDep($dep, $installcondition = false) - { - $structure = array( - 'pattern', - '*conflicts', - ); - $type = $installcondition ? '' : ''; - $this->_stupidSchemaValidate($structure, $dep, $type); - } - - function _validateInstallConditions($cond, $release) - { - $structure = array( - '*php', - '*extension', - '*os', - '*arch', - ); - if (!$this->_stupidSchemaValidate($structure, - $cond, $release)) { - return false; - } - foreach (array('php', 'extension', 'os', 'arch') as $type) { - if (isset($cond[$type])) { - $iter = $cond[$type]; - if (!is_array($iter) || !isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type == 'extension') { - $this->{"_validate{$type}Dep"}($package, false, true); - } else { - $this->{"_validate{$type}Dep"}($package, true); - } - } - } - } - } - - function _validateDependencies() - { - $structure = array( - 'required', - '*optional', - '*group->name->hint' - ); - if (!$this->_stupidSchemaValidate($structure, - $this->_packageInfo['dependencies'], '')) { - return false; - } - foreach (array('required', 'optional') as $simpledep) { - if (isset($this->_packageInfo['dependencies'][$simpledep])) { - if ($simpledep == 'optional') { - $structure = array( - '*package', - '*subpackage', - '*extension', - ); - } else { - $structure = array( - 'php', - 'pearinstaller', - '*package', - '*subpackage', - '*extension', - '*os', - '*arch', - ); - } - if ($this->_stupidSchemaValidate($structure, - $this->_packageInfo['dependencies'][$simpledep], - "<$simpledep>")) { - foreach (array('package', 'subpackage', 'extension') as $type) { - if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { - $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type != 'extension') { - if (isset($package['uri'])) { - if (isset($package['channel'])) { - $this->_UrlOrChannel($type, - $package['name']); - } - } else { - if (!isset($package['channel'])) { - $this->_NoChannel($type, $package['name']); - } - } - } - $this->{"_validate{$type}Dep"}($package, "<$simpledep>"); - } - } - } - if ($simpledep == 'optional') { - continue; - } - foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) { - if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { - $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - $this->{"_validate{$type}Dep"}($package); - } - } - } - } - } - } - if (isset($this->_packageInfo['dependencies']['group'])) { - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } - $structure = array( - '*package', - '*subpackage', - '*extension', - ); - foreach ($groups as $group) { - if ($this->_stupidSchemaValidate($structure, $group, '')) { - if (!PEAR_Validate::validGroupName($group['attribs']['name'])) { - $this->_invalidDepGroupName($group['attribs']['name']); - } - foreach (array('package', 'subpackage', 'extension') as $type) { - if (isset($group[$type])) { - $iter = $group[$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type != 'extension') { - if (isset($package['uri'])) { - if (isset($package['channel'])) { - $this->_UrlOrChannelGroup($type, - $package['name'], - $group['name']); - } - } else { - if (!isset($package['channel'])) { - $this->_NoChannelGroup($type, - $package['name'], - $group['name']); - } - } - } - $this->{"_validate{$type}Dep"}($package, ''); - } - } - } - } - } - } - } - - function _validateCompatible() - { - $compat = $this->_packageInfo['compatible']; - if (!isset($compat[0])) { - $compat = array($compat); - } - $required = array('name', 'channel', 'min', 'max', '*exclude'); - foreach ($compat as $package) { - $type = ''; - if (is_array($package) && array_key_exists('name', $package)) { - $type .= '' . $package['name'] . ''; - } - $this->_stupidSchemaValidate($required, $package, $type); - if (is_array($package) && array_key_exists('min', $package)) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $package['min'])) { - $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_NoBundledPackages(); - } - if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) { - return $this->_AtLeast2BundledPackages(); - } - foreach ($list['bundledpackage'] as $package) { - if (!is_string($package)) { - $this->_bundledPackagesMustBeFilename(); - } - } - } - - function _validateFilelist($list = false, $allowignore = false, $dirs = '') - { - $iscontents = false; - if (!$list) { - $iscontents = true; - $list = $this->_packageInfo['contents']; - if (isset($this->_packageInfo['bundle'])) { - return $this->_validateBundle($list); - } - } - if ($allowignore) { - $struc = array( - '*install->name->as', - '*ignore->name' - ); - } else { - $struc = array( - '*dir->name->?baseinstalldir', - '*file->name->role->?baseinstalldir->?md5sum' - ); - if (isset($list['dir']) && isset($list['file'])) { - // stave off validation errors without requiring a set order. - $_old = $list; - if (isset($list['attribs'])) { - $list = array('attribs' => $_old['attribs']); - } - $list['dir'] = $_old['dir']; - $list['file'] = $_old['file']; - } - } - if (!isset($list['attribs']) || !isset($list['attribs']['name'])) { - $unknown = $allowignore ? '' : ''; - $dirname = $iscontents ? '' : $unknown; - } else { - $dirname = ''; - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $list['attribs']['name']))) { - // file contains .. parent directory or . cur directory - $this->_invalidDirName($list['attribs']['name']); - } - } - $res = $this->_stupidSchemaValidate($struc, $list, $dirname); - if ($allowignore && $res) { - $ignored_or_installed = array(); - $this->_pf->getFilelist(); - $fcontents = $this->_pf->getContents(); - $filelist = array(); - if (!isset($fcontents['dir']['file'][0])) { - $fcontents['dir']['file'] = array($fcontents['dir']['file']); - } - foreach ($fcontents['dir']['file'] as $file) { - $filelist[$file['attribs']['name']] = true; - } - if (isset($list['install'])) { - if (!isset($list['install'][0])) { - $list['install'] = array($list['install']); - } - foreach ($list['install'] as $file) { - if (!isset($filelist[$file['attribs']['name']])) { - $this->_notInContents($file['attribs']['name'], 'install'); - continue; - } - if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { - $this->_multipleInstallAs($file['attribs']['name']); - } - if (!isset($ignored_or_installed[$file['attribs']['name']])) { - $ignored_or_installed[$file['attribs']['name']] = array(); - } - $ignored_or_installed[$file['attribs']['name']][] = 1; - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $file['attribs']['as']))) { - // file contains .. parent directory or . cur directory references - $this->_invalidFileInstallAs($file['attribs']['name'], - $file['attribs']['as']); - } - } - } - if (isset($list['ignore'])) { - if (!isset($list['ignore'][0])) { - $list['ignore'] = array($list['ignore']); - } - foreach ($list['ignore'] as $file) { - if (!isset($filelist[$file['attribs']['name']])) { - $this->_notInContents($file['attribs']['name'], 'ignore'); - continue; - } - if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { - $this->_ignoreAndInstallAs($file['attribs']['name']); - } - } - } - } - if (!$allowignore && isset($list['file'])) { - if (is_string($list['file'])) { - $this->_oldStyleFileNotAllowed(); - return false; - } - if (!isset($list['file'][0])) { - // single file - $list['file'] = array($list['file']); - } - foreach ($list['file'] as $i => $file) - { - if (isset($file['attribs']) && isset($file['attribs']['name'])) { - if ($file['attribs']['name']{0} == '.' && - $file['attribs']['name']{1} == '/') { - // name is something like "./doc/whatever.txt" - $this->_invalidFileName($file['attribs']['name'], $dirname); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $file['attribs']['name']))) { - // file contains .. parent directory or . cur directory - $this->_invalidFileName($file['attribs']['name'], $dirname); - } - } - if (isset($file['attribs']) && isset($file['attribs']['role'])) { - if (!$this->_validateRole($file['attribs']['role'])) { - if (isset($this->_packageInfo['usesrole'])) { - $roles = $this->_packageInfo['usesrole']; - if (!isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if ($role['role'] = $file['attribs']['role']) { - $msg = 'This package contains role "%role%" and requires ' . - 'package "%package%" to be used'; - if (isset($role['uri'])) { - $params = array('role' => $role['role'], - 'package' => $role['uri']); - } else { - $params = array('role' => $role['role'], - 'package' => $this->_pf->_registry-> - parsedPackageNameToString(array('package' => - $role['package'], 'channel' => $role['channel']), - true)); - } - $this->_stack->push('_mustInstallRole', 'error', $params, $msg); - } - } - } - $this->_invalidFileRole($file['attribs']['name'], - $dirname, $file['attribs']['role']); - } - } - if (!isset($file['attribs'])) { - continue; - } - $save = $file['attribs']; - if ($dirs) { - $save['name'] = $dirs . '/' . $save['name']; - } - unset($file['attribs']); - if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks - foreach ($file as $task => $value) { - if ($tagClass = $this->_pf->getTask($task)) { - if (!is_array($value) || !isset($value[0])) { - $value = array($value); - } - foreach ($value as $v) { - $ret = call_user_func(array($tagClass, 'validateXml'), - $this->_pf, $v, $this->_pf->_config, $save); - if (is_array($ret)) { - $this->_invalidTask($task, $ret, isset($save['name']) ? - $save['name'] : ''); - } - } - } else { - if (isset($this->_packageInfo['usestask'])) { - $roles = $this->_packageInfo['usestask']; - if (!isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if ($role['task'] = $task) { - $msg = 'This package contains task "%task%" and requires ' . - 'package "%package%" to be used'; - if (isset($role['uri'])) { - $params = array('task' => $role['task'], - 'package' => $role['uri']); - } else { - $params = array('task' => $role['task'], - 'package' => $this->_pf->_registry-> - parsedPackageNameToString(array('package' => - $role['package'], 'channel' => $role['channel']), - true)); - } - $this->_stack->push('_mustInstallTask', 'error', - $params, $msg); - } - } - } - $this->_unknownTask($task, $save['name']); - } - } - } - } - } - if (isset($list['ignore'])) { - if (!$allowignore) { - $this->_ignoreNotAllowed('ignore'); - } - } - if (isset($list['install'])) { - if (!$allowignore) { - $this->_ignoreNotAllowed('install'); - } - } - if (isset($list['file'])) { - if ($allowignore) { - $this->_fileNotAllowed('file'); - } - } - if (isset($list['dir'])) { - if ($allowignore) { - $this->_fileNotAllowed('dir'); - } else { - if (!isset($list['dir'][0])) { - $list['dir'] = array($list['dir']); - } - foreach ($list['dir'] as $dir) { - if (isset($dir['attribs']) && isset($dir['attribs']['name'])) { - if ($dir['attribs']['name'] == '/' || - !isset($this->_packageInfo['contents']['dir']['dir'])) { - // always use nothing if the filelist has already been flattened - $newdirs = ''; - } elseif ($dirs == '') { - $newdirs = $dir['attribs']['name']; - } else { - $newdirs = $dirs . '/' . $dir['attribs']['name']; - } - } else { - $newdirs = $dirs; - } - $this->_validateFilelist($dir, $allowignore, $newdirs); - } - } - } - } - - function _validateRelease() - { - if (isset($this->_packageInfo['phprelease'])) { - $release = 'phprelease'; - if (isset($this->_packageInfo['providesextension'])) { - $this->_cannotProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo['phprelease']; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, ''); - } - } - foreach (array('', 'zend') as $prefix) { - $releasetype = $prefix . 'extsrcrelease'; - if (isset($this->_packageInfo[$releasetype])) { - $release = $releasetype; - if (!isset($this->_packageInfo['providesextension'])) { - $this->_mustProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo[$releasetype]; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*configureoption->name->prompt->?default', - '*binarypackage', - '*filelist', - ), $rel, '<' . $releasetype . '>'); - if (isset($rel['binarypackage'])) { - if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) { - $rel['binarypackage'] = array($rel['binarypackage']); - } - foreach ($rel['binarypackage'] as $bin) { - if (!is_string($bin)) { - $this->_binaryPackageMustBePackagename(); - } - } - } - } - } - $releasetype = 'extbinrelease'; - if (isset($this->_packageInfo[$releasetype])) { - $release = $releasetype; - if (!isset($this->_packageInfo['providesextension'])) { - $this->_mustProvideExtension($release); - } - if (isset($this->_packageInfo['channel']) && - !isset($this->_packageInfo['srcpackage'])) { - $this->_mustSrcPackage($release); - } - if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) { - $this->_mustSrcuri($release); - } - $releases = $this->_packageInfo[$releasetype]; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, '<' . $releasetype . '>'); - } - } - } - if (isset($this->_packageInfo['bundle'])) { - $release = 'bundle'; - if (isset($this->_packageInfo['providesextension'])) { - $this->_cannotProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo['bundle']; - if (!is_array($releases) || !isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, ''); - } - } - foreach ($releases as $rel) { - if (is_array($rel) && array_key_exists('installconditions', $rel)) { - $this->_validateInstallConditions($rel['installconditions'], - "<$release>"); - } - if (is_array($rel) && array_key_exists('filelist', $rel)) { - if ($rel['filelist']) { - - $this->_validateFilelist($rel['filelist'], true); - } - } - } - } - - /** - * This is here to allow role extension through plugins - * @param string - */ - function _validateRole($role) - { - return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())); - } - - function _pearVersionTooLow($version) - { - $this->_stack->push(__FUNCTION__, 'error', - array('version' => $version), - 'This package.xml requires PEAR version %version% to parse properly, we are ' . - 'version 1.9.0'); - } - - function _invalidTagOrder($oktags, $actual, $root) - { - $this->_stack->push(__FUNCTION__, 'error', - array('oktags' => $oktags, 'actual' => $actual, 'root' => $root), - 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"'); - } - - function _ignoreNotAllowed($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '<%type%> is not allowed inside global , only inside ' . - '//, use and only'); - } - - function _fileNotAllowed($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '<%type%> is not allowed inside release , only inside ' . - ', use and only'); - } - - function _oldStyleFileNotAllowed() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Old-style name is not allowed. Use' . - ''); - } - - function _tagMissingAttribute($tag, $attr, $context) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, - 'attribute' => $attr, 'context' => $context), - 'tag <%tag%> in context "%context%" has no attribute "%attribute%"'); - } - - function _tagHasNoAttribs($tag, $context) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, - 'context' => $context), - 'tag <%tag%> has no attributes in context "%context%"'); - } - - function _invalidInternalStructure() - { - $this->_stack->push(__FUNCTION__, 'exception', array(), - 'internal array was not generated by compatible parser, or extreme parser error, cannot continue'); - } - - function _invalidFileRole($file, $dir, $role) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file, 'dir' => $dir, 'role' => $role, - 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())), - 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%'); - } - - function _invalidFileName($file, $dir) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file), - 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."'); - } - - function _invalidFileInstallAs($file, $as) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file, 'as' => $as), - 'File "%file%" cannot contain "./" or contain ".."'); - } - - function _invalidDirName($dir) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'dir' => $file), - 'Directory "%dir%" cannot begin with "./" or contain ".."'); - } - - function _filelistCannotContainFile($filelist) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), - '<%tag%> can only contain , contains . Use ' . - ' as the first dir element'); - } - - function _filelistMustContainDir($filelist) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), - '<%tag%> must contain . Use as the ' . - 'first dir element'); - } - - function _tagCannotBeEmpty($tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), - '<%tag%> cannot be empty (<%tag%/>)'); - } - - function _UrlOrChannel($type, $name) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name), - 'Required dependency <%type%> "%name%" can have either url OR ' . - 'channel attributes, and not both'); - } - - function _NoChannel($type, $name) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name), - 'Required dependency <%type%> "%name%" must have either url OR ' . - 'channel attributes'); - } - - function _UrlOrChannelGroup($type, $name, $group) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name, 'group' => $group), - 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' . - 'channel attributes, and not both'); - } - - function _NoChannelGroup($type, $name, $group) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name, 'group' => $group), - 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' . - 'channel attributes'); - } - - function _unknownChannel($channel) - { - $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel), - 'Unknown channel "%channel%"'); - } - - function _noPackageVersion() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'package.xml tag has no version attribute, or version is not 2.0'); - } - - function _NoBundledPackages() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'No tag was found in , required for bundle packages'); - } - - function _AtLeast2BundledPackages() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'At least 2 packages must be bundled in a bundle package'); - } - - function _ChannelOrUri($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Bundled package "%name%" can have either a uri or a channel, not both'); - } - - function _noChildTag($child, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag), - 'Tag <%tag%> is missing child tag <%child%>'); - } - - function _invalidVersion($type, $value) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value), - 'Version type <%type%> is not a valid version (%value%)'); - } - - function _invalidState($type, $value) - { - $states = array('stable', 'beta', 'alpha', 'devel'); - if ($type != 'api') { - $states[] = 'snapshot'; - } - if (strtolower($value) == 'rc') { - $this->_stack->push(__FUNCTION__, 'error', - array('version' => $this->_packageInfo['version']['release']), - 'RC is not a state, it is a version postfix, try %version%RC1, stability beta'); - } - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value, - 'types' => $states), - 'Stability type <%type%> is not a valid stability (%value%), must be one of ' . - '%types%'); - } - - function _invalidTask($task, $ret, $file) - { - switch ($ret[0]) { - case PEAR_TASK_ERROR_MISSING_ATTRIB : - $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%'; - break; - case PEAR_TASK_ERROR_NOATTRIBS : - $info = array('task' => $task, 'file' => $file); - $msg = 'task <%task%> has no attributes in file %file%'; - break; - case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE : - $info = array('attrib' => $ret[1], 'values' => $ret[3], - 'was' => $ret[2], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '. - 'in file %file%, expecting one of "%values%"'; - break; - case PEAR_TASK_ERROR_INVALID : - $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> in file %file% is invalid because of "%reason%"'; - break; - } - $this->_stack->push(__FUNCTION__, 'error', $info, $msg); - } - - function _unknownTask($task, $file) - { - $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file), - 'Unknown task "%task%" passed in file '); - } - - function _subpackageCannotProvideExtension($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Subpackage dependency "%name%" cannot use , ' . - 'only package dependencies can use this tag'); - } - - function _subpackagesCannotConflict($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Subpackage dependency "%name%" cannot use , ' . - 'only package dependencies can use this tag'); - } - - function _cannotProvideExtension($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages cannot use , only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension'); - } - - function _mustProvideExtension($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages must use to indicate which PHP extension is provided'); - } - - function _cannotHaveSrcpackage($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages cannot specify a source code package, only extension binaries may use the tag'); - } - - function _mustSrcPackage($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '/ packages must specify a source code package with '); - } - - function _mustSrcuri($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '/ packages must specify a source code package with '); - } - - function _uriDepsCannotHaveVersioning($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: dependencies with a tag cannot have any versioning information'); - } - - function _conflictingDepsCannotHaveVersioning($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: conflicting dependencies cannot have versioning info, use to ' . - 'exclude specific versions of a dependency'); - } - - function _DepchannelCannotBeUri($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' . - 'dependencies only'); - } - - function _bundledPackagesMustBeFilename() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - ' tags must contain only the filename of a package release ' . - 'in the bundle'); - } - - function _binaryPackageMustBePackagename() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - ' tags must contain the name of a package that is ' . - 'a compiled version of this extsrc/zendextsrc package'); - } - - function _fileNotFound($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'File "%file%" in package.xml does not exist'); - } - - function _notInContents($file, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag), - '<%tag% name="%file%"> is invalid, file is not in '); - } - - function _cannotValidateNoPathSet() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Cannot validate files, no path to package file is set (use setPackageFile())'); - } - - function _usesroletaskMustHaveChannelOrUri($role, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), - '<%tag%> for role "%role%" must contain either , or and '); - } - - function _usesroletaskMustHavePackage($role, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), - '<%tag%> for role "%role%" must contain '); - } - - function _usesroletaskMustHaveRoleTask($tag, $type) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type), - '<%tag%> must contain <%type%> defining the %type% to be used'); - } - - function _cannotConflictWithAllOs($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), - '%tag% cannot conflict with all OSes'); - } - - function _invalidDepGroupName($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Invalid dependency group name "%name%"'); - } - - function _multipleToplevelDirNotAllowed() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Multiple top-level tags are not allowed. Enclose them ' . - 'in a '); - } - - function _multipleInstallAs($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Only one tag is allowed for file "%file%"'); - } - - function _ignoreAndInstallAs($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Cannot have both and tags for file "%file%"'); - } - - function _analyzeBundledPackages() - { - if (!$this->_isValid) { - return false; - } - if (!$this->_pf->getPackageType() == 'bundle') { - return false; - } - if (!isset($this->_pf->_packageFile)) { - return false; - } - $dir_prefix = dirname($this->_pf->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : - array($common, 'log'); - $info = $this->_pf->getContents(); - $info = $info['bundledpackage']; - if (!is_array($info)) { - $info = array($info); - } - $pkg = &new PEAR_PackageFile($this->_pf->_config); - foreach ($info as $package) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) { - $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package); - $this->_isValid = 0; - continue; - } - call_user_func_array($log, array(1, "Analyzing bundled package $package")); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package, - PEAR_VALIDATE_NORMAL); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - call_user_func_array($log, array(0, "ERROR: package $package is not a valid " . - 'package')); - $inf = $ret->getUserInfo(); - if (is_array($inf)) { - foreach ($inf as $err) { - call_user_func_array($log, array(1, $err['message'])); - } - } - return false; - } - } - return true; - } - - function _analyzePhpFiles() - { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_pf->_packageFile)) { - $this->_cannotValidateNoPathSet(); - return false; - } - $dir_prefix = dirname($this->_pf->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : - array(&$common, 'log'); - $info = $this->_pf->getContents(); - if (!$info || !isset($info['dir']['file'])) { - $this->_tagCannotBeEmpty('contents>_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); - $this->_isValid = 0; - continue; - } - if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); - } - } - } - $this->_packageName = $pn = $this->_pf->getPackage(); - $pnl = strlen($pn); - foreach ($provides as $key => $what) { - if (isset($what['explicit']) || !$what) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), - 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), - 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); - } - } - return $this->_isValid; - } - - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @param boolean whether to analyze $file as the file contents - * @return mixed - */ - function analyzeSourceCode($file, $string = false) - { - if (!function_exists("token_get_all")) { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer'); - return false; - } - - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); - } - - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); - } - - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); - } - - if ($string) { - $contents = $file; - } else { - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); - } - - // Silence this function so we can catch PHP Warnings and show our own custom message - $tokens = @token_get_all($contents); - if (isset($php_errormsg)) { - if (isset($this->_stack)) { - $pn = $this->_pf->getPackage(); - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'package' => $pn), - 'in %file%: Could not process file for unkown reasons,' . - ' possibly a PHP parse error in %file% from %package%'); - } - } -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); - } - } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; - } - - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; - } - } - - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Parser error: invalid PHP found in file "%file%"'); - } else { - PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", - PEAR_COMMON_ERROR_INVALIDPHP); - } - - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - ) - ) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'warning', array( - 'file' => $file), - 'Error, PHP5 token encountered in %file%,' . - ' analysis should be in PHP5'); - } else { - PEAR::raiseError('Error: PHP5 token encountered in ' . $file . - 'packaging should be done in PHP 5'); - return false; - } - } - } - - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } - - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; - } - - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } - } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file), - 'Parser error: invalid PHP found in file "%file%"'); - } else { - PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", - PEAR_COMMON_ERROR_INVALIDPHP); - } - - return false; - } - - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; - } - - continue 2; - } - } - - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * - */ - function _buildProvidesArray($srcinfo) - { - if (!$this->_isValid) { - return array(); - } - - $providesret = array(); - $file = basename($srcinfo['source_file']); - $pn = isset($this->_pf) ? $this->_pf->getPackage() : ''; - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($providesret[$key])) { - continue; - } - - $providesret[$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $providesret[$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($providesret[$key])) { - continue; - } - - $providesret[$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($providesret[$key])) { - continue; - } - - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - - $providesret[$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - - return $providesret; - } -}PEAR-1.9.0/PEAR/PackageFile/v1.php100664 764 764 143760 100664 11302 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling - */ -require_once 'PEAR/ErrorStack.php'; - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); - -/** - * Error code used when there is no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); - -/** - * Error code when a package name is not valid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); - -/** - * Error code used when no summary is parsed - */ -define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); - -/** - * Error code for summaries that are more than 1 line - */ -define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); - -/** - * Error code used when no description is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); - -/** - * Error code used when no license is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); - -/** - * Error code used when a version number is not present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); - -/** - * Error code used when a version number is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); - -/** - * Error code when no release notes are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); - -/** - * Error code when no maintainers are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); - -/** - * Error code when a maintainer has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); - -/** - * Error code when a maintainer has no email - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); - -/** - * Error code when a dependency is not a PHP dependency, but has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); - -/** - * Error code when a dependency has no type (pkg, php, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); - -/** - * Error code when a dependency has no relation (lt, ge, has, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); - -/** - * Error code when a dependency is not a 'has' relation, but has no version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); - -/** - * Error code when a dependency has an invalid relation - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); - -/** - * Error code when a dependency has an invalid type - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); - -/** - * Error code when a dependency has an invalid optional option - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); - -/** - * Error code when a dependency is a pkg dependency, and has an invalid package name - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); - -/** - * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); - -/** - * Error code when rel="has" and version attribute is present. - */ -define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); - -/** - * Error code when type="php" and dependency name is present - */ -define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); - -/** - * Error code when a file in the filelist has an invalid role - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); - -/** - * Error code when a file in the filelist has no role - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); - -/** - * Error code when analyzing a php source file that has parse errors - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); - -/** - * Error code when analyzing a php source file reveals a source element - * without a package name prefix - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); - -/** - * Error code when an unknown channel is specified - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); - -/** - * Error code when no files are found in the filelist - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); - -/** - * Error code when a file is not valid php according to _analyzeSourceCode() - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); - -/** - * Error code when the channel validator returns an error or warning - */ -define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); - -/** - * Error code when a php5 package is packaged in php4 (analysis doesn't work) - */ -define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); - -/** - * Error code when a file is listed in package.xml but does not exist - */ -define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); - -/** - * Error code when a - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_v1 -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * A registry object, used to access the package name validation regex for non-standard channels - * @var PEAR_Registry - * @access private - */ - var $_registry; - - /** - * An object that contains a log method that matches PEAR_Common::log's signature - * @var object - * @access private - */ - var $_logger; - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo; - - /** - * path to package.xml - * @var string - * @access private - */ - var $_packageFile; - - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string - * @access private - */ - var $_archiveFile; - - /** - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; - - /** - * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack - * @param string Name of Error Stack class to use. - */ - function PEAR_PackageFile_v1() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = 0; - } - - function installBinary($installer) - { - return false; - } - - function isExtension($name) - { - return false; - } - - function setConfig(&$config) - { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); - } - - function setRequestedGroup() - { - // placeholder - } - - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) - { - $this->_packageInfo['_lastversion'] = $version; - } - - /** - * @return string|false - */ - function getLastInstalledVersion() - { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; - } - return false; - } - - function getInstalledBinary() - { - return false; - } - - function listPostinstallScripts() - { - return false; - } - - function initPostinstallScripts() - { - return false; - } - - function setLogger(&$logger) - { - if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; - } - - function setPackagefile($file, $archive = false) - { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; - } - - function getPackageFile() - { - return isset($this->_packageFile) ? $this->_packageFile : false; - } - - function getPackageType() - { - return 'php'; - } - - function getArchiveFile() - { - return $this->_archiveFile; - } - - function packageInfo($field) - { - if (!is_string($field) || empty($field) || - !isset($this->_packageInfo[$field])) { - return false; - } - return $this->_packageInfo[$field]; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); - } - - function fromArray($pinfo) - { - $this->_incomplete = false; - $this->_packageInfo = $pinfo; - } - - function isIncomplete() - { - return $this->_incomplete; - } - - function getChannel() - { - return 'pear.php.net'; - } - - function getUri() - { - return false; - } - - function getTime() - { - return false; - } - - function getExtends() - { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; - } - - /** - * @return array - */ - function toArray() - { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray(); - } - - function getArray() - { - return $this->_packageInfo; - } - - function getName() - { - return $this->getPackage(); - } - - function getPackage() - { - if (isset($this->_packageInfo['package'])) { - return $this->_packageInfo['package']; - } - return false; - } - - /** - * WARNING - don't use this unless you know what you are doing - */ - function setRawPackage($package) - { - $this->_packageInfo['package'] = $package; - } - - function setPackage($package) - { - $this->_packageInfo['package'] = $package; - $this->_isValid = false; - } - - function getVersion() - { - if (isset($this->_packageInfo['version'])) { - return $this->_packageInfo['version']; - } - return false; - } - - function setVersion($version) - { - $this->_packageInfo['version'] = $version; - $this->_isValid = false; - } - - function clearMaintainers() - { - unset($this->_packageInfo['maintainers']); - } - - function getMaintainers() - { - if (isset($this->_packageInfo['maintainers'])) { - return $this->_packageInfo['maintainers']; - } - return false; - } - - /** - * Adds a new maintainer - no checking of duplicates is performed, use - * updatemaintainer for that purpose. - */ - function addMaintainer($role, $handle, $name, $email) - { - $this->_packageInfo['maintainers'][] = - array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); - $this->_isValid = false; - } - - function updateMaintainer($role, $handle, $name, $email) - { - $found = false; - if (!isset($this->_packageInfo['maintainers']) || - !is_array($this->_packageInfo['maintainers'])) { - return $this->addMaintainer($role, $handle, $name, $email); - } - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - } - $this->addMaintainer($role, $handle, $name, $email); - } - - function deleteMaintainer($handle) - { - $found = false; - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - return true; - } - return false; - } - - function getState() - { - if (isset($this->_packageInfo['release_state'])) { - return $this->_packageInfo['release_state']; - } - return false; - } - - function setRawState($state) - { - $this->_packageInfo['release_state'] = $state; - } - - function setState($state) - { - $this->_packageInfo['release_state'] = $state; - $this->_isValid = false; - } - - function getDate() - { - if (isset($this->_packageInfo['release_date'])) { - return $this->_packageInfo['release_date']; - } - return false; - } - - function setDate($date) - { - $this->_packageInfo['release_date'] = $date; - $this->_isValid = false; - } - - function getLicense() - { - if (isset($this->_packageInfo['release_license'])) { - return $this->_packageInfo['release_license']; - } - return false; - } - - function setLicense($date) - { - $this->_packageInfo['release_license'] = $date; - $this->_isValid = false; - } - - function getSummary() - { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; - } - - function setSummary($summary) - { - $this->_packageInfo['summary'] = $summary; - $this->_isValid = false; - } - - function getDescription() - { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; - } - - function setDescription($desc) - { - $this->_packageInfo['description'] = $desc; - $this->_isValid = false; - } - - function getNotes() - { - if (isset($this->_packageInfo['release_notes'])) { - return $this->_packageInfo['release_notes']; - } - return false; - } - - function setNotes($notes) - { - $this->_packageInfo['release_notes'] = $notes; - $this->_isValid = false; - } - - function getDeps() - { - if (isset($this->_packageInfo['release_deps'])) { - return $this->_packageInfo['release_deps']; - } - return false; - } - - /** - * Reset dependencies prior to adding new ones - */ - function clearDeps() - { - unset($this->_packageInfo['release_deps']); - } - - function addPhpDep($version, $rel) - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'php', - 'rel' => $rel, - 'version' => $version); - } - - function addPackageDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $dep = - array('type' => 'pkg', - 'name' => $name, - 'rel' => $rel, - 'optional' => $optional); - if ($rel != 'has' && $rel != 'not') { - $dep['version'] = $version; - } - $this->_packageInfo['release_deps'][] = $dep; - } - - function addExtensionDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'ext', - 'name' => $name, - 'rel' => $rel, - 'version' => $version, - 'optional' => $optional); - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) - { - $this->_packageInfo['release_deps'] = $deps; - } - - function hasDeps() - { - return isset($this->_packageInfo['release_deps']) && - count($this->_packageInfo['release_deps']); - } - - function getDependencyGroup($group) - { - return false; - } - - function isCompatible($pf) - { - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); - } - - function isSubpackage($p) - { - return false; - } - - function dependsOn($package, $channel) - { - if (strtolower($channel) != 'pear.php.net') { - return false; - } - if (!($deps = $this->getDeps())) { - return false; - } - foreach ($deps as $dep) { - if ($dep['type'] != 'pkg') { - continue; - } - if (strtolower($dep['name']) == strtolower($package)) { - return true; - } - } - return false; - } - - function getConfigureOptions() - { - if (isset($this->_packageInfo['configure_options'])) { - return $this->_packageInfo['configure_options']; - } - return false; - } - - function hasConfigureOptions() - { - return isset($this->_packageInfo['configure_options']) && - count($this->_packageInfo['configure_options']); - } - - function addConfigureOption($name, $prompt, $default = false) - { - $o = array('name' => $name, 'prompt' => $prompt); - if ($default !== false) { - $o['default'] = $default; - } - if (!isset($this->_packageInfo['configure_options'])) { - $this->_packageInfo['configure_options'] = array(); - } - $this->_packageInfo['configure_options'][] = $o; - } - - function clearConfigureOptions() - { - unset($this->_packageInfo['configure_options']); - } - - function getProvides() - { - if (isset($this->_packageInfo['provides'])) { - return $this->_packageInfo['provides']; - } - return false; - } - - function getProvidesExtension() - { - return false; - } - - function addFile($dir, $file, $attrs) - { - $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); - if ($dir == '/' || $dir == '') { - $dir = ''; - } else { - $dir .= '/'; - } - $file = $dir . $file; - $file = preg_replace('![\\/]+!', '/', $file); - $this->_packageInfo['filelist'][$file] = $attrs; - } - - function getInstallationFilelist() - { - return $this->getFilelist(); - } - - function getFilelist() - { - if (isset($this->_packageInfo['filelist'])) { - return $this->_packageInfo['filelist']; - } - return false; - } - - function setFileAttribute($file, $attr, $value) - { - $this->_packageInfo['filelist'][$file][$attr] = $value; - } - - function resetFilelist() - { - $this->_packageInfo['filelist'] = array(); - } - - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts); - } else { - $this->_packageInfo['filelist'][$file] = $atts; - } - } - - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } - - function getPackagexmlVersion() - { - return '1.0'; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) - { - return $this->_stack->getErrors($purge); - } - - // }}} - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); - $this->_isValid = false; - } - - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); - } - - /** - * @param integer error code - * @access protected - */ - function _getErrorMessage() - { - return array( - PEAR_PACKAGEFILE_ERROR_NO_NAME => - 'Missing Package Name', - PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => - 'No summary found', - PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => - 'Summary should be on one line', - PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => - 'Missing description', - PEAR_PACKAGEFILE_ERROR_NO_LICENSE => - 'Missing license', - PEAR_PACKAGEFILE_ERROR_NO_VERSION => - 'No release version found', - PEAR_PACKAGEFILE_ERROR_NO_STATE => - 'No release state found', - PEAR_PACKAGEFILE_ERROR_NO_DATE => - 'No release date found', - PEAR_PACKAGEFILE_ERROR_NO_NOTES => - 'No release notes found', - PEAR_PACKAGEFILE_ERROR_NO_LEAD => - 'Package must have at least one lead maintainer', - PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => - 'No maintainers found, at least one must be defined', - PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => - 'Maintainer %index% has no handle (user ID at channel server)', - PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => - 'Maintainer %index% has no role', - PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => - 'Maintainer %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => - 'Maintainer %index% has no email', - PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => - 'Dependency %index% is not a php dependency, and has no name', - PEAR_PACKAGEFILE_ERROR_NO_DEPREL => - 'Dependency %index% has no relation (rel)', - PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => - 'Dependency %index% has no type', - PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => - 'PHP Dependency %index% has a name attribute of "%name%" which will be' . - ' ignored!', - PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => - 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => - 'Dependency %index% is a type="php" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => - 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', - PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => - 'Dependency %index% has invalid optional value "%opt%", should be yes or no', - PEAR_PACKAGEFILE_PHP_NO_NOT => - 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . - ' to exclude specific versions', - PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => - 'Configure Option %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => - 'Configure Option %index% has no prompt', - PEAR_PACKAGEFILE_ERROR_NO_FILES => - 'No files in section of package.xml', - PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => - 'File "%file%" has no role, expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => - 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => - 'File "%file%" cannot start with ".", cannot package or install', - PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => - 'Parser error: invalid PHP found in file "%file%"', - PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => - 'in %file%: %type% "%name%" not prefixed with package name "%package%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILE => - 'Parser error: invalid PHP file "%file%"', - PEAR_PACKAGEFILE_ERROR_CHANNELVAL => - 'Channel validator error: field "%field%" - %reason%', - PEAR_PACKAGEFILE_ERROR_PHP5 => - 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', - PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => - 'File "%file%" in package.xml does not exist', - PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => - 'Package.xml contains non-ISO-8859-1 characters, and may not validate', - ); - } - - /** - * Validate XML package definition file. - * - * @access public - * @return boolean - */ - function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) - { - if (($this->_isValid & $state) == $state) { - return true; - } - $this->_isValid = true; - $info = $this->_packageInfo; - if (empty($info['package'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); - $this->_packageName = $pn = 'unknown'; - } else { - $this->_packageName = $pn = $info['package']; - } - - if (empty($info['summary'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (empty($info['description'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); - } - if (empty($info['release_license'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); - } - if (empty($info['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); - } - if (empty($info['release_state'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); - } - if (empty($info['release_date'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); - } - if (empty($info['release_notes'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); - } - if (empty($info['maintainers'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); - } else { - $haslead = false; - $i = 1; - foreach ($info['maintainers'] as $m) { - if (empty($m['handle'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, - array('index' => $i)); - } - if (empty($m['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, - array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); - } elseif ($m['role'] == 'lead') { - $haslead = true; - } - if (empty($m['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, - array('index' => $i)); - } - if (empty($m['email'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, - array('index' => $i)); - } - $i++; - } - if (!$haslead) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); - } - } - if (!empty($info['release_deps'])) { - $i = 1; - foreach ($info['release_deps'] as $d) { - if (!isset($d['type']) || empty($d['type'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, - array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); - continue; - } - if (!isset($d['rel']) || empty($d['rel'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, - array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); - continue; - } - if (!empty($d['optional'])) { - if (!in_array($d['optional'], array('yes', 'no'))) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, - array('index' => $i, 'opt' => $d['optional'])); - } - } - if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, - array('index' => $i)); - } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, - array('index' => $i, 'rel' => $d['rel'])); - } - if ($d['type'] == 'php' && !empty($d['name'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, - array('index' => $i, 'name' => $d['name'])); - } elseif ($d['type'] != 'php' && empty($d['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, - array('index' => $i)); - } - if ($d['type'] == 'php' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, - array('index' => $i)); - } - if (($d['rel'] == 'not') && ($d['type'] == 'php')) { - $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, - array('index' => $i)); - } - $i++; - } - } - if (!empty($info['configure_options'])) { - $i = 1; - foreach ($info['configure_options'] as $c) { - if (empty($c['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, - array('index' => $i)); - } - if (empty($c['prompt'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, - array('index' => $i)); - } - $i++; - } - } - if (empty($info['filelist'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); - $errors[] = 'no files'; - } else { - foreach ($info['filelist'] as $file => $fa) { - if (empty($fa['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, - array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); - continue; - } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, - array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { - // file contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file)); - } - if (isset($fa['install-as']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['install-as']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); - } - if (isset($fa['baseinstalldir']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['baseinstalldir']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); - } - } - } - if (isset($this->_registry) && $this->_isValid) { - $chan = $this->_registry->getChannel('pear.php.net'); - if (PEAR::isError($chan)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); - return $this->_isValid = 0; - } - $validator = $chan->getValidationObject(); - $validator->setPackageFile($this); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); - } - foreach ($failures['warnings'] as $warning) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); - } - } - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { - if ($this->_analyzePhpFiles()) { - $this->_isValid = true; - } - } - if ($this->_isValid) { - return $this->_isValid = $state; - } - return $this->_isValid = 0; - } - - function _analyzePhpFiles() - { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_packageFile)) { - return false; - } - $dir_prefix = dirname($this->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_logger) ? array(&$this->_logger, 'log') : - array($common, 'log'); - $info = $this->getFilelist(); - foreach ($info as $file => $fa) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, - array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); - continue; - } - if ($fa['role'] == 'php' && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $this->_buildProvidesArray($srcinfo); - } - } - } - $this->_packageName = $pn = $this->getPackage(); - $pnl = strlen($pn); - if (isset($this->_packageInfo['provides'])) { - foreach ((array) $this->_packageInfo['provides'] as $key => $what) { - if (isset($what['explicit'])) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } - } - } - return $this->_isValid; - } - - /** - * Get the default xml generator object - * - * @return PEAR_PackageFile_Generator_v1 - */ - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v1')) { - require_once 'PEAR/PackageFile/Generator/v1.php'; - } - $a = &new PEAR_PackageFile_Generator_v1($this); - return $a; - } - - /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string - */ - function getFileContents($file) - { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - if (!class_exists('Archive_Tar')) { - require_once 'Archive/Tar.php'; - } - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - // {{{ analyzeSourceCode() - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access private - */ - function _analyzeSourceCode($file) - { - if (!function_exists("token_get_all")) { - return false; - } - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); - } - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); - } - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); - } - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); - $tokens = token_get_all($contents); -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); - } - } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; - } - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; - } - } - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - )) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, - array($file)); - } - } - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; - } - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } - } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; - } - continue 2; - } - } - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * - */ - function _buildProvidesArray($srcinfo) - { - if (!$this->_isValid) { - return false; - } - $file = basename($srcinfo['source_file']); - $pn = $this->getPackage(); - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->_packageInfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { - continue; - } - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - // }}} -} -?> -PEAR-1.9.0/PEAR/PackageFile/v2.php100664 764 764 207576 100664 11311 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling - */ -require_once 'PEAR/ErrorStack.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_v2 -{ - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo = array(); - - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string|false - * @access private - */ - var $_archiveFile; - - /** - * path to package .xml or false if this is an abstract parsed-from-string xml - * @var string|false - * @access private - */ - var $_packageFile; - - /** - * This is used by file analysis routines to log progress information - * @var PEAR_Common - * @access protected - */ - var $_logger; - - /** - * This is set to the highest validation level that has been validated - * - * If the package.xml is invalid or unknown, this is set to 0. If - * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If - * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING - * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation - * "caching" to occur, which is particularly important for package validation, so - * that PHP files are not validated twice - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * True if the filelist has been validated - * @param bool - */ - var $_filesValid = false; - - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * @var PEAR_Config - * @access protected - */ - var $_config; - - /** - * Optional Dependency group requested for installation - * @var string - * @access private - */ - var $_requestedGroup = false; - - /** - * @var PEAR_ErrorStack - * @access protected - */ - var $_stack; - - /** - * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible - */ - var $_tasksNs; - - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; - - /** - * @var PEAR_PackageFile_v2_Validator - */ - var $_v2Validator; - - /** - * The constructor merely sets up the private error stack - */ - function PEAR_PackageFile_v2() - { - $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); - $this->_isValid = false; - } - - /** - * To make unit-testing easier - * @param PEAR_Frontend_* - * @param array options - * @param PEAR_Config - * @return PEAR_Downloader - * @access protected - */ - function &getPEARDownloader(&$i, $o, &$c) - { - $z = &new PEAR_Downloader($i, $o, $c); - return $z; - } - - /** - * To make unit-testing easier - * @param PEAR_Config - * @param array options - * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} - * @param int PEAR_VALIDATE_* constant - * @return PEAR_Dependency2 - * @access protected - */ - function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) - { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - $z = &new PEAR_Dependency2($c, $o, $p, $s); - return $z; - } - - function getInstalledBinary() - { - return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : - false; - } - - /** - * Installation of source package has failed, attempt to download and install the - * binary version of this package. - * @param PEAR_Installer - * @return array|false - */ - function installBinary(&$installer) - { - if (!OS_WINDOWS) { - $a = false; - return $a; - } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $releasetype = $this->getPackageType() . 'release'; - if (!is_array($installer->getInstallPackages())) { - $a = false; - return $a; - } - foreach ($installer->getInstallPackages() as $p) { - if ($p->isExtension($this->_packageInfo['providesextension'])) { - if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { - $a = false; - return $a; // the user probably downloaded it separately - } - } - } - if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { - $installer->log(0, 'Attempting to download binary version of extension "' . - $this->_packageInfo['providesextension'] . '"'); - $params = $this->_packageInfo[$releasetype]['binarypackage']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); - } - if (isset($this->_packageInfo['channel'])) { - foreach ($params as $i => $param) { - $params[$i] = array('channel' => $this->_packageInfo['channel'], - 'package' => $param, 'version' => $this->getVersion()); - } - } - $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), - $installer->config); - $verbose = $dl->config->get('verbose'); - $dl->config->set('verbose', -1); - foreach ($params as $param) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $dl->download(array($param)); - PEAR::popErrorHandling(); - if (is_array($ret) && count($ret)) { - break; - } - } - $dl->config->set('verbose', $verbose); - if (is_array($ret)) { - if (count($ret) == 1) { - $pf = $ret[0]->getPackageFile(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $installer->install($ret[0]); - PEAR::popErrorHandling(); - if (is_array($err)) { - $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); - // "install" self, so all dependencies will work transparently - $this->_registry->addPackage2($this); - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" successful'); - $a = array($ret[0], $err); - return $a; - } - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" failed'); - } - } - } - } - $a = false; - return $a; - } - - /** - * @return string|false Extension name - */ - function getProvidesExtension() - { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - if (isset($this->_packageInfo['providesextension'])) { - return $this->_packageInfo['providesextension']; - } - } - return false; - } - - /** - * @param string Extension name - * @return bool - */ - function isExtension($extension) - { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - return $this->_packageInfo['providesextension'] == $extension; - } - return false; - } - - /** - * Tests whether every part of the package.xml 1.0 is represented in - * this package.xml 2.0 - * @param PEAR_PackageFile_v1 - * @return bool - */ - function isEquivalent($pf1) - { - if (!$pf1) { - return true; - } - if ($this->getPackageType() == 'bundle') { - return false; - } - $this->_stack->getErrors(true); - if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - $pass = true; - if ($pf1->getPackage() != $this->getPackage()) { - $this->_differentPackage($pf1->getPackage()); - $pass = false; - } - if ($pf1->getVersion() != $this->getVersion()) { - $this->_differentVersion($pf1->getVersion()); - $pass = false; - } - if (trim($pf1->getSummary()) != $this->getSummary()) { - $this->_differentSummary($pf1->getSummary()); - $pass = false; - } - if (preg_replace('/\s+/', '', $pf1->getDescription()) != - preg_replace('/\s+/', '', $this->getDescription())) { - $this->_differentDescription($pf1->getDescription()); - $pass = false; - } - if ($pf1->getState() != $this->getState()) { - $this->_differentState($pf1->getState()); - $pass = false; - } - if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), - preg_replace('/\s+/', '', $pf1->getNotes()))) { - $this->_differentNotes($pf1->getNotes()); - $pass = false; - } - $mymaintainers = $this->getMaintainers(); - $yourmaintainers = $pf1->getMaintainers(); - for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { - $reset = false; - for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { - if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { - if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { - $this->_differentRole($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); - $pass = false; - } - if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { - $this->_differentEmail($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); - $pass = false; - } - if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { - $this->_differentName($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); - $pass = false; - } - unset($mymaintainers[$i2]); - $mymaintainers = array_values($mymaintainers); - unset($yourmaintainers[$i1]); - $yourmaintainers = array_values($yourmaintainers); - $reset = true; - break; - } - } - if ($reset) { - $i1 = -1; - } - } - $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); - $filelist = $this->getFilelist(); - foreach ($pf1->getFilelist() as $file => $atts) { - if (!isset($filelist[$file])) { - $this->_missingFile($file); - $pass = false; - } - } - return $pass; - } - - function _differentPackage($package) - { - $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, - 'self' => $this->getPackage()), - 'package.xml 1.0 package "%package%" does not match "%self%"'); - } - - function _differentVersion($version) - { - $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, - 'self' => $this->getVersion()), - 'package.xml 1.0 version "%version%" does not match "%self%"'); - } - - function _differentState($state) - { - $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, - 'self' => $this->getState()), - 'package.xml 1.0 state "%state%" does not match "%self%"'); - } - - function _differentRole($handle, $role, $selfrole) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'role' => $role, 'self' => $selfrole), - 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); - } - - function _differentEmail($handle, $email, $selfemail) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'email' => $email, 'self' => $selfemail), - 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); - } - - function _differentName($handle, $name, $selfname) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'name' => $name, 'self' => $selfname), - 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); - } - - function _unmatchedMaintainers($my, $yours) - { - if ($my) { - array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), - 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); - } - if ($yours) { - array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), - 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); - } - } - - function _differentNotes($notes) - { - $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; - $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : - substr($this->getNotes(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, - 'self' => $truncmynotes), - 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); - } - - function _differentSummary($summary) - { - $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; - $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : - substr($this->getsummary(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, - 'self' => $truncmysummary), - 'package.xml 1.0 summary "%summary%" does not match "%self%"'); - } - - function _differentDescription($description) - { - $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); - $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : - substr($this->getdescription(), 0, 24) . '...'); - $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, - 'self' => $truncmydescription), - 'package.xml 1.0 description "%description%" does not match "%self%"'); - } - - function _missingFile($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'package.xml 1.0 file "%file%" is not present in '); - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawState($state) - { - if (!isset($this->_packageInfo['stability'])) { - $this->_packageInfo['stability'] = array(); - } - $this->_packageInfo['stability']['release'] = $state; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawCompatible($compatible) - { - $this->_packageInfo['compatible'] = $compatible; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawPackage($package) - { - $this->_packageInfo['name'] = $package; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawChannel($channel) - { - $this->_packageInfo['channel'] = $channel; - } - - function setRequestedGroup($group) - { - $this->_requestedGroup = $group; - } - - function getRequestedGroup() - { - if (isset($this->_requestedGroup)) { - return $this->_requestedGroup; - } - return false; - } - - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) - { - $this->_packageInfo['_lastversion'] = $version; - } - - /** - * @return string|false - */ - function getLastInstalledVersion() - { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; - } - return false; - } - - /** - * Determines whether this package.xml has post-install scripts or not - * @return array|false - */ - function listPostinstallScripts() - { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); - } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; - } - } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - $ret = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // ignored files will not be in the filelist - continue; - } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $task = $this->getTask($tag); - $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); - if ($task->isScript()) { - $ret[] = $filelist[$name]['installed_as']; - } - } - } - if (count($ret)) { - return $ret; - } - return false; - } - - /** - * Initialize post-install scripts for running - * - * This method can be used to detect post-install scripts, as the return value - * indicates whether any exist - * @return bool - */ - function initPostinstallScripts() - { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); - } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; - } - } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // file was not installed due to installconditions - continue; - } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $taskname = $this->getTask($tag); - $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); - if (!$task->isScript()) { - continue; // scripts are only handled after installation - } - $lastversion = isset($this->_packageInfo['_lastversion']) ? - $this->_packageInfo['_lastversion'] : null; - $task->init($raw, $atts, $lastversion); - $res = $task->startSession($this, $atts['installed_as']); - if (!$res) { - continue; // skip this file - } - if (PEAR::isError($res)) { - return $res; - } - $assign = &$task; - $this->_scripts[] = &$assign; - } - } - if (count($this->_scripts)) { - return true; - } - return false; - } - - function runPostinstallScripts() - { - if ($this->initPostinstallScripts()) { - $ui = &PEAR_Frontend::singleton(); - if ($ui) { - $ui->runPostinstallScripts($this->_scripts, $this); - } - } - } - - - /** - * Convert a recursive set of and tags into a single tag with - * tags. - */ - function flattenFilelist() - { - if (isset($this->_packageInfo['bundle'])) { - return; - } - $filelist = array(); - if (isset($this->_packageInfo['contents']['dir']['dir'])) { - $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); - if (!isset($filelist[1])) { - $filelist = $filelist[0]; - } - $this->_packageInfo['contents']['dir']['file'] = $filelist; - unset($this->_packageInfo['contents']['dir']['dir']); - } else { - // else already flattened but check for baseinstalldir propagation - if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { - if (isset($this->_packageInfo['contents']['dir']['file'][0])) { - foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { - if (isset($file['attribs']['baseinstalldir'])) { - continue; - } - $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } else { - if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { - $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } - } - } - } - - /** - * @param array the final flattened file list - * @param array the current directory being processed - * @param string|false any recursively inherited baeinstalldir attribute - * @param string private recursion variable - * @return array - * @access protected - */ - function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') - { - if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { - $baseinstall = $dir['attribs']['baseinstalldir']; - } - if (isset($dir['dir'])) { - if (!isset($dir['dir'][0])) { - $dir['dir'] = array($dir['dir']); - } - foreach ($dir['dir'] as $subdir) { - if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { - $name = '*unknown*'; - } else { - $name = $subdir['attribs']['name']; - } - $newpath = empty($path) ? $name : - $path . '/' . $name; - $this->_getFlattenedFilelist($files, $subdir, - $baseinstall, $newpath); - } - } - if (isset($dir['file'])) { - if (!isset($dir['file'][0])) { - $dir['file'] = array($dir['file']); - } - foreach ($dir['file'] as $file) { - $attrs = $file['attribs']; - $name = $attrs['name']; - if ($baseinstall && !isset($attrs['baseinstalldir'])) { - $attrs['baseinstalldir'] = $baseinstall; - } - $attrs['name'] = empty($path) ? $name : $path . '/' . $name; - $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attrs['name']); - $file['attribs'] = $attrs; - $files[] = $file; - } - } - } - - function setConfig(&$config) - { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); - } - - function setLogger(&$logger) - { - if (!is_object($logger) || !method_exists($logger, 'log')) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) - { - $this->_packageInfo['dependencies'] = $deps; - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setCompatible($compat) - { - $this->_packageInfo['compatible'] = $compat; - } - - function setPackagefile($file, $archive = false) - { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) - { - return $this->_stack->getErrors($purge); - } - - function getPackageFile() - { - return $this->_packageFile; - } - - function getArchiveFile() - { - return $this->_archiveFile; - } - - - /** - * Directly set the array that defines this packagefile - * - * WARNING: no validation. This should only be performed by internal methods - * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 - * @param array - */ - function fromArray($pinfo) - { - unset($pinfo['old']); - unset($pinfo['xsdversion']); - $this->_incomplete = false; - $this->_packageInfo = $pinfo; - } - - function isIncomplete() - { - return $this->_incomplete; - } - - /** - * @return array - */ - function toArray($forreg = false) - { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray($forreg); - } - - function getArray($forReg = false) - { - if ($forReg) { - $arr = $this->_packageInfo; - $arr['old'] = array(); - $arr['old']['version'] = $this->getVersion(); - $arr['old']['release_date'] = $this->getDate(); - $arr['old']['release_state'] = $this->getState(); - $arr['old']['release_license'] = $this->getLicense(); - $arr['old']['release_notes'] = $this->getNotes(); - $arr['old']['release_deps'] = $this->getDeps(); - $arr['old']['maintainers'] = $this->getMaintainers(); - $arr['xsdversion'] = '2.0'; - return $arr; - } else { - $info = $this->_packageInfo; - unset($info['dirtree']); - if (isset($info['_lastversion'])) { - unset($info['_lastversion']); - } - if (isset($info['#binarypackage'])) { - unset($info['#binarypackage']); - } - return $info; - } - } - - function packageInfo($field) - { - $arr = $this->getArray(true); - if ($field == 'state') { - return $arr['stability']['release']; - } - if ($field == 'api-version') { - return $arr['version']['api']; - } - if ($field == 'api-state') { - return $arr['stability']['api']; - } - if (isset($arr['old'][$field])) { - if (!is_string($arr['old'][$field])) { - return null; - } - return $arr['old'][$field]; - } - if (isset($arr[$field])) { - if (!is_string($arr[$field])) { - return null; - } - return $arr[$field]; - } - return null; - } - - function getName() - { - return $this->getPackage(); - } - - function getPackage() - { - if (isset($this->_packageInfo['name'])) { - return $this->_packageInfo['name']; - } - return false; - } - - function getChannel() - { - if (isset($this->_packageInfo['uri'])) { - return '__uri'; - } - if (isset($this->_packageInfo['channel'])) { - return strtolower($this->_packageInfo['channel']); - } - return false; - } - - function getUri() - { - if (isset($this->_packageInfo['uri'])) { - return $this->_packageInfo['uri']; - } - return false; - } - - function getExtends() - { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; - } - - function getSummary() - { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; - } - - function getDescription() - { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; - } - - function getMaintainers($raw = false) - { - if (!isset($this->_packageInfo['lead'])) { - return false; - } - if ($raw) { - $ret = array('lead' => $this->_packageInfo['lead']); - (isset($this->_packageInfo['developer'])) ? - $ret['developer'] = $this->_packageInfo['developer'] :null; - (isset($this->_packageInfo['contributor'])) ? - $ret['contributor'] = $this->_packageInfo['contributor'] :null; - (isset($this->_packageInfo['helper'])) ? - $ret['helper'] = $this->_packageInfo['helper'] :null; - return $ret; - } else { - $ret = array(); - $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : - array($this->_packageInfo['lead']); - foreach ($leads as $lead) { - $s = $lead; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'lead'; - $ret[] = $s; - } - if (isset($this->_packageInfo['developer'])) { - $leads = isset($this->_packageInfo['developer'][0]) ? - $this->_packageInfo['developer'] : - array($this->_packageInfo['developer']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'developer'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['contributor'])) { - $leads = isset($this->_packageInfo['contributor'][0]) ? - $this->_packageInfo['contributor'] : - array($this->_packageInfo['contributor']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'contributor'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['helper'])) { - $leads = isset($this->_packageInfo['helper'][0]) ? - $this->_packageInfo['helper'] : - array($this->_packageInfo['helper']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'helper'; - $ret[] = $s; - } - } - return $ret; - } - return false; - } - - function getLeads() - { - if (isset($this->_packageInfo['lead'])) { - return $this->_packageInfo['lead']; - } - return false; - } - - function getDevelopers() - { - if (isset($this->_packageInfo['developer'])) { - return $this->_packageInfo['developer']; - } - return false; - } - - function getContributors() - { - if (isset($this->_packageInfo['contributor'])) { - return $this->_packageInfo['contributor']; - } - return false; - } - - function getHelpers() - { - if (isset($this->_packageInfo['helper'])) { - return $this->_packageInfo['helper']; - } - return false; - } - - function setDate($date) - { - if (!isset($this->_packageInfo['date'])) { - // ensure that the extends tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); - } - $this->_packageInfo['date'] = $date; - $this->_isValid = 0; - } - - function setTime($time) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['time'])) { - // ensure that the time tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); - } - $this->_packageInfo['time'] = $time; - } - - function getDate() - { - if (isset($this->_packageInfo['date'])) { - return $this->_packageInfo['date']; - } - return false; - } - - function getTime() - { - if (isset($this->_packageInfo['time'])) { - return $this->_packageInfo['time']; - } - return false; - } - - /** - * @param package|api version category to return - */ - function getVersion($key = 'release') - { - if (isset($this->_packageInfo['version'][$key])) { - return $this->_packageInfo['version'][$key]; - } - return false; - } - - function getStability() - { - if (isset($this->_packageInfo['stability'])) { - return $this->_packageInfo['stability']; - } - return false; - } - - function getState($key = 'release') - { - if (isset($this->_packageInfo['stability'][$key])) { - return $this->_packageInfo['stability'][$key]; - } - return false; - } - - function getLicense($raw = false) - { - if (isset($this->_packageInfo['license'])) { - if ($raw) { - return $this->_packageInfo['license']; - } - if (is_array($this->_packageInfo['license'])) { - return $this->_packageInfo['license']['_content']; - } else { - return $this->_packageInfo['license']; - } - } - return false; - } - - function getLicenseLocation() - { - if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { - return false; - } - return $this->_packageInfo['license']['attribs']; - } - - function getNotes() - { - if (isset($this->_packageInfo['notes'])) { - return $this->_packageInfo['notes']; - } - return false; - } - - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsesrole() - { - if (isset($this->_packageInfo['usesrole'])) { - return $this->_packageInfo['usesrole']; - } - return false; - } - - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsestask() - { - if (isset($this->_packageInfo['usestask'])) { - return $this->_packageInfo['usestask']; - } - return false; - } - - /** - * This should only be used to retrieve filenames and install attributes - */ - function getFilelist($preserve = false) - { - if (isset($this->_packageInfo['filelist']) && !$preserve) { - return $this->_packageInfo['filelist']; - } - $this->flattenFilelist(); - if ($contents = $this->getContents()) { - $ret = array(); - if (!isset($contents['dir'])) { - return false; - } - if (!isset($contents['dir']['file'][0])) { - $contents['dir']['file'] = array($contents['dir']['file']); - } - foreach ($contents['dir']['file'] as $file) { - $name = $file['attribs']['name']; - if (!$preserve) { - $file = $file['attribs']; - } - $ret[$name] = $file; - } - if (!$preserve) { - $this->_packageInfo['filelist'] = $ret; - } - return $ret; - } - return false; - } - - /** - * Return configure options array, if any - * - * @return array|false - */ - function getConfigureOptions() - { - if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { - return false; - } - - $releases = $this->getReleases(); - if (isset($releases[0])) { - $releases = $releases[0]; - } - - if (isset($releases['configureoption'])) { - if (!isset($releases['configureoption'][0])) { - $releases['configureoption'] = array($releases['configureoption']); - } - - for ($i = 0; $i < count($releases['configureoption']); $i++) { - $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; - } - - return $releases['configureoption']; - } - - return false; - } - - /** - * This is only used at install-time, after all serialization - * is over. - */ - function resetFilelist() - { - $this->_packageInfo['filelist'] = array(); - } - - /** - * Retrieve a list of files that should be installed on this computer - * @return array - */ - function getInstallationFilelist($forfilecheck = false) - { - $contents = $this->getFilelist(true); - if (isset($contents['dir']['attribs']['baseinstalldir'])) { - $base = $contents['dir']['attribs']['baseinstalldir']; - } - if (isset($this->_packageInfo['bundle'])) { - return PEAR::raiseError( - 'Exception: bundles should be handled in download code only'); - } - $release = $this->getReleases(); - if ($release) { - if (!isset($release[0])) { - if (!isset($release['installconditions']) && !isset($release['filelist'])) { - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - $release = array($release); - } - $depchecker = &$this->getPEARDependency2($this->_config, array(), - array('channel' => $this->getChannel(), 'package' => $this->getPackage()), - PEAR_VALIDATE_INSTALLING); - foreach ($release as $instance) { - if (isset($instance['installconditions'])) { - $installconditions = $instance['installconditions']; - if (is_array($installconditions)) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($installconditions as $type => $conditions) { - if (!isset($conditions[0])) { - $conditions = array($conditions); - } - foreach ($conditions as $condition) { - $ret = $depchecker->{"validate{$type}Dependency"}($condition); - if (PEAR::isError($ret)) { - PEAR::popErrorHandling(); - continue 3; // skip this release - } - } - } - PEAR::popErrorHandling(); - } - } - // this is the release to use - if (isset($instance['filelist'])) { - // ignore files - if (isset($instance['filelist']['ignore'])) { - $ignore = isset($instance['filelist']['ignore'][0]) ? - $instance['filelist']['ignore'] : - array($instance['filelist']['ignore']); - foreach ($ignore as $ig) { - unset ($contents[$ig['attribs']['name']]); - } - } - // install files as this name - if (isset($instance['filelist']['install'])) { - $installas = isset($instance['filelist']['install'][0]) ? - $instance['filelist']['install'] : - array($instance['filelist']['install']); - foreach ($installas as $as) { - $contents[$as['attribs']['name']]['attribs']['install-as'] = - $as['attribs']['as']; - } - } - } - if ($forfilecheck) { - foreach ($contents as $file => $attrs) { - $contents[$file] = $attrs['attribs']; - } - } - return $contents; - } - } else { // simple release - no installconditions or install-as - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - // no releases matched - return PEAR::raiseError('No releases in package.xml matched the existing operating ' . - 'system, extensions installed, or architecture, cannot install'); - } - - /** - * This is only used at install-time, after all serialization - * is over. - * @param string file name - * @param string installed path - */ - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function getInstalledLocation($file) - { - if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { - return $this->_packageInfo['filelist'][$file]['installed_as']; - } - return false; - } - - /** - * This is only used at install-time, after all serialization - * is over. - */ - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); - } else { - $this->_packageInfo['filelist'][$file] = $atts['attribs']; - } - } - - /** - * Retrieve the contents tag - */ - function getContents() - { - if (isset($this->_packageInfo['contents'])) { - return $this->_packageInfo['contents']; - } - return false; - } - - /** - * @param string full path to file - * @param string attribute name - * @param string attribute value - * @param int risky but fast - use this to choose a file based on its position in the list - * of files. Index is zero-based like PHP arrays. - * @return bool success of operation - */ - function setFileAttribute($filename, $attr, $value, $index = false) - { - $this->_isValid = 0; - if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { - $this->_filesValid = false; - } - if ($index !== false && - isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { - $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; - return true; - } - if (!isset($this->_packageInfo['contents']['dir']['file'])) { - return false; - } - $files = $this->_packageInfo['contents']['dir']['file']; - if (!isset($files[0])) { - $files = array($files); - $ind = false; - } else { - $ind = true; - } - foreach ($files as $i => $file) { - if (isset($file['attribs'])) { - if ($file['attribs']['name'] == $filename) { - if ($ind) { - $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; - } else { - $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; - } - return true; - } - } - } - return false; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); - } - - /** - * Determines whether this package claims it is compatible with the version of - * the package that has a recommended version dependency - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package - * @return boolean - */ - function isCompatible($pf) - { - if (!isset($this->_packageInfo['compatible'])) { - return false; - } - if (!isset($this->_packageInfo['channel'])) { - return false; - } - $me = $pf->getVersion(); - $compatible = $this->_packageInfo['compatible']; - if (!isset($compatible[0])) { - $compatible = array($compatible); - } - $found = false; - foreach ($compatible as $info) { - if (strtolower($info['name']) == strtolower($pf->getPackage())) { - if (strtolower($info['channel']) == strtolower($pf->getChannel())) { - $found = true; - break; - } - } - } - if (!$found) { - return false; - } - if (isset($info['exclude'])) { - if (!isset($info['exclude'][0])) { - $info['exclude'] = array($info['exclude']); - } - foreach ($info['exclude'] as $exclude) { - if (version_compare($me, $exclude, '==')) { - return false; - } - } - } - if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { - return true; - } - return false; - } - - /** - * @return array|false - */ - function getCompatible() - { - if (isset($this->_packageInfo['compatible'])) { - return $this->_packageInfo['compatible']; - } - return false; - } - - function getDependencies() - { - if (isset($this->_packageInfo['dependencies'])) { - return $this->_packageInfo['dependencies']; - } - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); - } - - /** - * Determines whether the passed in package is a subpackage of this package. - * - * No version checking is done, only name verification. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - */ - function isSubpackage($p) - { - $sub = array(); - if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { - $sub = $this->_packageInfo['dependencies']['required']['subpackage']; - if (!isset($sub[0])) { - $sub = array($sub); - } - } - if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { - $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; - if (!isset($sub1[0])) { - $sub1 = array($sub1); - } - $sub = array_merge($sub, $sub1); - } - if (isset($this->_packageInfo['dependencies']['group'])) { - $group = $this->_packageInfo['dependencies']['group']; - if (!isset($group[0])) { - $group = array($group); - } - foreach ($group as $deps) { - if (isset($deps['subpackage'])) { - $sub2 = $deps['subpackage']; - if (!isset($sub2[0])) { - $sub2 = array($sub2); - } - $sub = array_merge($sub, $sub2); - } - } - } - foreach ($sub as $dep) { - if (strtolower($dep['name']) == strtolower($p->getPackage())) { - if (isset($dep['channel'])) { - if (strtolower($dep['channel']) == strtolower($p->getChannel())) { - return true; - } - } else { - if ($dep['uri'] == $p->getURI()) { - return true; - } - } - } - } - return false; - } - - function dependsOn($package, $channel) - { - if (!($deps = $this->getDependencies())) { - return false; - } - foreach (array('package', 'subpackage') as $type) { - foreach (array('required', 'optional') as $needed) { - if (isset($deps[$needed][$type])) { - if (!isset($deps[$needed][$type][0])) { - $deps[$needed][$type] = array($deps[$needed][$type]); - } - foreach ($deps[$needed][$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } - } - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $dep['group'] = array($deps['group']); - } - foreach ($deps['group'] as $group) { - if (isset($group[$type])) { - if (!is_array($group[$type])) { - $group[$type] = array($group[$type]); - } - foreach ($group[$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } - } - } - } - return false; - } - - /** - * Get the contents of a dependency group - * @param string - * @return array|false - */ - function getDependencyGroup($name) - { - $name = strtolower($name); - if (!isset($this->_packageInfo['dependencies']['group'])) { - return false; - } - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } - foreach ($groups as $group) { - if (strtolower($group['attribs']['name']) == $name) { - return $group; - } - } - return false; - } - - /** - * Retrieve a partial package.xml 1.0 representation of dependencies - * - * a very limited representation of dependencies is returned by this method. - * The tag for excluding certain versions of a dependency is - * completely ignored. In addition, dependency groups are ignored, with the - * assumption that all dependencies in dependency groups are also listed in - * the optional group that work with all dependency groups - * @param boolean return package.xml 2.0 tag - * @return array|false - */ - function getDeps($raw = false, $nopearinstaller = false) - { - if (isset($this->_packageInfo['dependencies'])) { - if ($raw) { - return $this->_packageInfo['dependencies']; - } - $ret = array(); - $map = array( - 'php' => 'php', - 'package' => 'pkg', - 'subpackage' => 'pkg', - 'extension' => 'ext', - 'os' => 'os', - 'pearinstaller' => 'pkg', - ); - foreach (array('required', 'optional') as $type) { - $optional = ($type == 'optional') ? 'yes' : 'no'; - if (!isset($this->_packageInfo['dependencies'][$type]) - || empty($this->_packageInfo['dependencies'][$type])) { - continue; - } - foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { - if ($dtype == 'pearinstaller' && $nopearinstaller) { - continue; - } - if (!isset($deps[0])) { - $deps = array($deps); - } - foreach ($deps as $dep) { - if (!isset($map[$dtype])) { - // no support for arch type - continue; - } - if ($dtype == 'pearinstaller') { - $dep['name'] = 'PEAR'; - $dep['channel'] = 'pear.php.net'; - } - $s = array('type' => $map[$dtype]); - if (isset($dep['channel'])) { - $s['channel'] = $dep['channel']; - } - if (isset($dep['uri'])) { - $s['uri'] = $dep['uri']; - } - if (isset($dep['name'])) { - $s['name'] = $dep['name']; - } - if (isset($dep['conflicts'])) { - $s['rel'] = 'not'; - } else { - if (!isset($dep['min']) && - !isset($dep['max'])) { - $s['rel'] = 'has'; - $s['optional'] = $optional; - } elseif (isset($dep['min']) && - isset($dep['max'])) { - $s['rel'] = 'ge'; - $s1 = $s; - $s1['rel'] = 'le'; - $s['version'] = $dep['min']; - $s1['version'] = $dep['max']; - if (isset($dep['channel'])) { - $s1['channel'] = $dep['channel']; - } - if ($dtype != 'php') { - $s['name'] = $dep['name']; - $s1['name'] = $dep['name']; - } - $s['optional'] = $optional; - $s1['optional'] = $optional; - $ret[] = $s1; - } elseif (isset($dep['min'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['min']) { - $s['rel'] = 'gt'; - } else { - $s['rel'] = 'ge'; - } - $s['version'] = $dep['min']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } elseif (isset($dep['max'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['max']) { - $s['rel'] = 'lt'; - } else { - $s['rel'] = 'le'; - } - $s['version'] = $dep['max']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } - } - $ret[] = $s; - } - } - } - if (count($ret)) { - return $ret; - } - } - return false; - } - - /** - * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false - */ - function getPackageType() - { - if (isset($this->_packageInfo['phprelease'])) { - return 'php'; - } - if (isset($this->_packageInfo['extsrcrelease'])) { - return 'extsrc'; - } - if (isset($this->_packageInfo['extbinrelease'])) { - return 'extbin'; - } - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return 'zendextsrc'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return 'zendextbin'; - } - if (isset($this->_packageInfo['bundle'])) { - return 'bundle'; - } - return false; - } - - /** - * @return array|false - */ - function getReleases() - { - $type = $this->getPackageType(); - if ($type != 'bundle') { - $type .= 'release'; - } - if ($this->getPackageType() && isset($this->_packageInfo[$type])) { - return $this->_packageInfo[$type]; - } - return false; - } - - /** - * @return array - */ - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } - - function hasDeps() - { - return isset($this->_packageInfo['dependencies']); - } - - function getPackagexmlVersion() - { - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return '2.1'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return '2.1'; - } - return '2.0'; - } - - /** - * @return array|false - */ - function getSourcePackage() - { - if (isset($this->_packageInfo['extbinrelease']) || - isset($this->_packageInfo['zendextbinrelease'])) { - return array('channel' => $this->_packageInfo['srcchannel'], - 'package' => $this->_packageInfo['srcpackage']); - } - return false; - } - - function getBundledPackages() - { - if (isset($this->_packageInfo['bundle'])) { - return $this->_packageInfo['contents']['bundledpackage']; - } - return false; - } - - function getLastModified() - { - if (isset($this->_packageInfo['_lastmodified'])) { - return $this->_packageInfo['_lastmodified']; - } - return false; - } - - /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string - */ - function getFileContents($file) - { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - function &getRW() - { - if (!class_exists('PEAR_PackageFile_v2_rw')) { - require_once 'PEAR/PackageFile/v2/rw.php'; - } - $a = new PEAR_PackageFile_v2_rw; - foreach (get_object_vars($this) as $name => $unused) { - if (!isset($this->$name)) { - continue; - } - if ($name == '_config' || $name == '_logger'|| $name == '_registry' || - $name == '_stack') { - $a->$name = &$this->$name; - } else { - $a->$name = $this->$name; - } - } - return $a; - } - - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v2')) { - require_once 'PEAR/PackageFile/Generator/v2.php'; - } - $a = &new PEAR_PackageFile_Generator_v2($this); - return $a; - } - - function analyzeSourceCode($file, $string = false) - { - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'PEAR/PackageFile/v2/Validator.php'; - } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; - } - return $this->_v2Validator->analyzeSourceCode($file, $string); - } - - function validate($state = PEAR_VALIDATE_NORMAL) - { - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { - return false; - } - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'PEAR/PackageFile/v2/Validator.php'; - } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; - } - if (isset($this->_packageInfo['xsdversion'])) { - unset($this->_packageInfo['xsdversion']); - } - return $this->_v2Validator->validate($this, $state); - } - - function getTasksNs() - { - if (!isset($this->_tasksNs)) { - if (isset($this->_packageInfo['attribs'])) { - foreach ($this->_packageInfo['attribs'] as $name => $value) { - if ($value == 'http://pear.php.net/dtd/tasks-1.0') { - $this->_tasksNs = str_replace('xmlns:', '', $name); - break; - } - } - } - } - return $this->_tasksNs; - } - - /** - * Determine whether a task name is a valid task. Custom tasks may be defined - * using subdirectories by putting a "-" in the name, as in - * - * Note that this method will auto-load the task class file and test for the existence - * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class - * PEAR_Task_mycustom_task - * @param string - * @return boolean - */ - function getTask($task) - { - $this->getTasksNs(); - // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace - $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); - $taskfile = str_replace(' ', '/', ucwords($task)); - $task = str_replace(array(' ', '/'), '_', ucwords($task)); - if (class_exists("PEAR_Task_$task")) { - return "PEAR_Task_$task"; - } - $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true); - if ($fp) { - fclose($fp); - require_once "PEAR/Task/$taskfile.php"; - return "PEAR_Task_$task"; - } - return false; - } - - /** - * Key-friendly array_splice - * @param tagname to splice a value in before - * @param mixed the value to splice in - * @param string the new tag name - */ - function _ksplice($array, $key, $value, $newkey) - { - $offset = array_search($key, array_keys($array)); - $after = array_slice($array, $offset); - $before = array_slice($array, 0, $offset); - $before[$newkey] = $value; - return array_merge($before, $after); - } - - /** - * @param array a list of possible keys, in the order they may occur - * @param mixed contents of the new package.xml tag - * @param string tag name - * @access private - */ - function _insertBefore($array, $keys, $contents, $newkey) - { - foreach ($keys as $key) { - if (isset($array[$key])) { - return $array = $this->_ksplice($array, $key, $contents, $newkey); - } - } - $array[$newkey] = $contents; - return $array; - } - - /** - * @param subsection of {@link $_packageInfo} - * @param array|string tag contents - * @param array format: - *
    -     * array(
    -     *   tagname => array(list of tag names that follow this one),
    -     *   childtagname => array(list of child tag names that follow this one),
    -     * )
    -     * 
    - * - * This allows construction of nested tags - * @access private - */ - function _mergeTag($manip, $contents, $order) - { - if (count($order)) { - foreach ($order as $tag => $curorder) { - if (!isset($manip[$tag])) { - // ensure that the tag is set up - $manip = $this->_insertBefore($manip, $curorder, array(), $tag); - } - if (count($order) > 1) { - $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); - return $manip; - } - } - } else { - return $manip; - } - if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { - $manip[$tag][] = $contents; - } else { - if (!count($manip[$tag])) { - $manip[$tag] = $contents; - } else { - $manip[$tag] = array($manip[$tag]); - $manip[$tag][] = $contents; - } - } - return $manip; - } -} -?> -PEAR-1.9.0/PEAR/REST/10.php100664 764 764 77605 100664 7602 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 10.php 287558 2009-08-21 22:21:28Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a12 - */ - -/** - * For downloading REST xml/txt files - */ -require_once 'PEAR/REST.php'; - -/** - * Implement REST 1.0 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a12 - */ -class PEAR_REST_10 -{ - /** - * @var PEAR_REST - */ - var $_rest; - function PEAR_REST_10($config, $options = array()) - { - $this->_rest = &new PEAR_REST($config, $options); - } - - /** - * Retrieve information about a remote package to be downloaded from a REST server - * - * @param string $base The uri to prepend to all REST calls - * @param array $packageinfo an array of format: - *
    -     *  array(
    -     *   'package' => 'packagename',
    -     *   'channel' => 'channelname',
    -     *  ['state' => 'alpha' (or valid state),]
    -     *  -or-
    -     *  ['version' => '1.whatever']
    -     * 
    - * @param string $prefstate Current preferred_state config variable value - * @param bool $installed the installed version of this package to compare against - * @return array|false|PEAR_Error see {@link _returnDownloadURL()} - */ - function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) - { - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $channel = $packageinfo['channel']; - $package = $packageinfo['package']; - $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; - $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; - $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; - - $info = $this->_rest->retrieveData($restFile, false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('No releases available for package "' . - $channel . '/' . $package . '"'); - } - - if (!isset($info['r'])) { - return false; - } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - - if (isset($state)) { - // try our preferred state first - if ($release['s'] == $state) { - $found = true; - break; - } - // see if there is something newer and more stable - // bug #7221 - if (in_array($release['s'], $this->betterStates($state), true)) { - $found = true; - break; - } - } elseif (isset($version)) { - if ($release['v'] == $version) { - $found = true; - break; - } - } else { - if (in_array($release['s'], $states)) { - $found = true; - break; - } - } - } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); - } - - function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, - $prefstate = 'stable', $installed = false, $channel = false) - { - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $channel = $dependency['channel']; - $package = $dependency['name']; - $state = isset($dependency['state']) ? $dependency['state'] : null; - $version = isset($dependency['version']) ? $dependency['version'] : null; - $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; - - $info = $this->_rest->retrieveData($restFile, false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] - . '" dependency "' . $channel . '/' . $package . '" has no releases'); - } - - if (!is_array($info) || !isset($info['r'])) { - return false; - } - - $exclude = array(); - $min = $max = $recommended = false; - if ($xsdversion == '1.0') { - switch ($dependency['rel']) { - case 'ge' : - $min = $dependency['version']; - break; - case 'gt' : - $min = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'eq' : - $recommended = $dependency['version']; - break; - case 'lt' : - $max = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'le' : - $max = $dependency['version']; - break; - case 'ne' : - $exclude = array($dependency['version']); - break; - } - } else { - $min = isset($dependency['min']) ? $dependency['min'] : false; - $max = isset($dependency['max']) ? $dependency['max'] : false; - $recommended = isset($dependency['recommended']) ? - $dependency['recommended'] : false; - if (isset($dependency['exclude'])) { - if (!isset($dependency['exclude'][0])) { - $exclude = array($dependency['exclude']); - } - } - } - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - if (in_array($release['v'], $exclude)) { // skip excluded versions - continue; - } - // allow newer releases to say "I'm OK with the dependent package" - if ($xsdversion == '2.0' && isset($release['co'])) { - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - foreach ($release['co'] as $entry) { - if (isset($entry['x']) && !is_array($entry['x'])) { - $entry['x'] = array($entry['x']); - } elseif (!isset($entry['x'])) { - $entry['x'] = array(); - } - if ($entry['c'] == $deppackage['channel'] && - strtolower($entry['p']) == strtolower($deppackage['package']) && - version_compare($deppackage['version'], $entry['min'], '>=') && - version_compare($deppackage['version'], $entry['max'], '<=') && - !in_array($release['v'], $entry['x'])) { - $recommended = $release['v']; - break; - } - } - } - if ($recommended) { - if ($release['v'] != $recommended) { // if we want a specific - // version, then skip all others - continue; - } else { - if (!in_array($release['s'], $states)) { - // the stability is too low, but we must return the - // recommended version if possible - return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); - } - } - } - if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions - continue; - } - if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions - continue; - } - if ($installed && version_compare($release['v'], $installed, '<')) { - continue; - } - if (in_array($release['s'], $states)) { // if in the preferred state... - $found = true; // ... then use it - break; - } - } - return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); - } - - /** - * Take raw data and return the array needed for processing a download URL - * - * @param string $base REST base uri - * @param string $package Package name - * @param array $release an array of format array('v' => version, 's' => state) - * describing the release to download - * @param array $info list of all releases as defined by allreleases.xml - * @param bool|null $found determines whether the release was found or this is the next - * best alternative. If null, then versions were skipped because - * of PHP dependency - * @return array|PEAR_Error - * @access private - */ - function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false) - { - if (!$found) { - $release = $info['r'][0]; - } - - $packageLower = strtolower($package); - $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' . - 'info.xml', false, false, $channel); - if (PEAR::isError($pinfo)) { - return PEAR::raiseError('Package "' . $package . - '" does not have REST info xml available'); - } - - $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . - $release['v'] . '.xml', false, false, $channel); - if (PEAR::isError($releaseinfo)) { - return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . - '" does not have REST xml available'); - } - - $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . - 'deps.' . $release['v'] . '.txt', false, true, $channel); - if (PEAR::isError($packagexml)) { - return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . - '" does not have REST dependency information available'); - } - - $packagexml = unserialize($packagexml); - if (!$packagexml) { - $packagexml = array(); - } - - $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower . - '/allreleases.xml', false, false, $channel); - if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { - $allinfo['r'] = array($allinfo['r']); - } - - $compatible = false; - foreach ($allinfo['r'] as $release) { - if ($release['v'] != $releaseinfo['v']) { - continue; - } - - if (!isset($release['co'])) { - break; - } - - $compatible = array(); - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - - foreach ($release['co'] as $entry) { - $comp = array(); - $comp['name'] = $entry['p']; - $comp['channel'] = $entry['c']; - $comp['min'] = $entry['min']; - $comp['max'] = $entry['max']; - if (isset($entry['x']) && !is_array($entry['x'])) { - $comp['exclude'] = $entry['x']; - } - - $compatible[] = $comp; - } - - if (count($compatible) == 1) { - $compatible = $compatible[0]; - } - - break; - } - - $deprecated = false; - if (isset($pinfo['dc']) && isset($pinfo['dp'])) { - if (is_array($pinfo['dp'])) { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp']['_content'])); - } else { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp'])); - } - } - - $return = array( - 'version' => $releaseinfo['v'], - 'info' => $packagexml, - 'package' => $releaseinfo['p']['_content'], - 'stability' => $releaseinfo['st'], - 'compatible' => $compatible, - 'deprecated' => $deprecated, - ); - - if ($found) { - $return['url'] = $releaseinfo['g']; - return $return; - } - - $return['php'] = $phpversion; - return $return; - } - - function listPackages($base, $channel = false) - { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return array(); - } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - return $packagelist['p']; - } - - /** - * List all categories of a REST server - * - * @param string $base base URL of the server - * @return array of categorynames - */ - function listCategories($base, $channel = false) - { - $categories = array(); - - // c/categories.xml does not exist; - // check for every package its category manually - // This is SLOOOWWWW : /// - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - if (!is_array($packagelist) || !isset($packagelist['p'])) { - $ret = array(); - return $ret; - } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($packagelist['p'] as $package) { - $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($inf)) { - PEAR::popErrorHandling(); - return $inf; - } - $cat = $inf['ca']['_content']; - if (!isset($categories[$cat])) { - $categories[$cat] = $inf['ca']; - } - } - - return array_values($categories); - } - - /** - * List a category of a REST server - * - * @param string $base base URL of the server - * @param string $category name of the category - * @param boolean $info also download full package info - * @return array of packagenames - */ - function listCategory($base, $category, $info = false, $channel = false) - { - // gives '404 Not Found' error when category doesn't exist - $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return array(); - } - - if (!is_array($packagelist['p']) || - !isset($packagelist['p'][0])) { // only 1 pkg - $packagelist = array($packagelist['p']); - } else { - $packagelist = $packagelist['p']; - } - - if ($info == true) { - // get individual package info - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($packagelist as $i => $packageitem) { - $url = sprintf('%s'.'r/%s/latest.txt', - $base, - strtolower($packageitem['_content'])); - $version = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($version)) { - break; // skipit - } - $url = sprintf('%s'.'r/%s/%s.xml', - $base, - strtolower($packageitem['_content']), - $version); - $info = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($info)) { - break; // skipit - } - $packagelist[$i]['info'] = $info; - } - PEAR::popErrorHandling(); - } - - return $packagelist; - } - - - function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) - { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if ($this->_rest->config->get('verbose') > 0) { - $ui = &PEAR_Frontend::singleton(); - $ui->log('Retrieving data...0%', true); - } - $ret = array(); - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return $ret; - } - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - // only search-packagename = quicksearch ! - if ($searchpackage && (!$searchsummary || empty($searchpackage))) { - $newpackagelist = array(); - foreach ($packagelist['p'] as $package) { - if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) { - $newpackagelist[] = $package; - } - } - $packagelist['p'] = $newpackagelist; - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $next = .1; - foreach ($packagelist['p'] as $progress => $package) { - if ($this->_rest->config->get('verbose') > 0) { - if ($progress / count($packagelist['p']) >= $next) { - if ($next == .5) { - $ui->log('50%', false); - } else { - $ui->log('.', false); - } - $next += .1; - } - } - - if ($basic) { // remote-list command - if ($dostable) { - $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/stable.txt', false, false, $channel); - } else { - $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/latest.txt', false, false, $channel); - } - if (PEAR::isError($latest)) { - $latest = false; - } - $info = array('stable' => $latest); - } else { // list-all command - $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($inf)) { - PEAR::popErrorHandling(); - return $inf; - } - if ($searchpackage) { - $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false); - if (!$found && !(isset($searchsummary) && !empty($searchsummary) - && (stristr($inf['s'], $searchsummary) !== false - || stristr($inf['d'], $searchsummary) !== false))) - { - continue; - }; - } - $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (PEAR::isError($releases)) { - continue; - } - if (!isset($releases['r'][0])) { - $releases['r'] = array($releases['r']); - } - unset($latest); - unset($unstable); - unset($stable); - unset($state); - foreach ($releases['r'] as $release) { - if (!isset($latest)) { - if ($dostable && $release['s'] == 'stable') { - $latest = $release['v']; - $state = 'stable'; - } - if (!$dostable) { - $latest = $release['v']; - $state = $release['s']; - } - } - if (!isset($stable) && $release['s'] == 'stable') { - $stable = $release['v']; - if (!isset($unstable)) { - $unstable = $stable; - } - } - if (!isset($unstable) && $release['s'] != 'stable') { - $latest = $unstable = $release['v']; - $state = $release['s']; - } - if (isset($latest) && !isset($state)) { - $state = $release['s']; - } - if (isset($latest) && isset($stable) && isset($unstable)) { - break; - } - } - $deps = array(); - if (!isset($unstable)) { - $unstable = false; - $state = 'stable'; - if (isset($stable)) { - $latest = $unstable = $stable; - } - } else { - $latest = $unstable; - } - if (!isset($latest)) { - $latest = false; - } - if ($latest) { - $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . - $latest . '.txt', false, false, $channel); - if (!PEAR::isError($d)) { - $d = unserialize($d); - if ($d) { - if (isset($d['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } - if (!isset($pf)) { - $pf = new PEAR_PackageFile_v2; - } - $pf->setDeps($d); - $tdeps = $pf->getDeps(); - } else { - $tdeps = $d; - } - foreach ($tdeps as $dep) { - if ($dep['type'] !== 'pkg') { - continue; - } - $deps[] = $dep; - } - } - } - } - if (!isset($stable)) { - $stable = '-n/a-'; - } - if (!$searchpackage) { - $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' => - $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - } else { - $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' => - $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - } - } - $ret[$package] = $info; - } - PEAR::popErrorHandling(); - return $ret; - } - - function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg) - { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - $ret = array(); - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return $ret; - } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - foreach ($packagelist['p'] as $package) { - if (!isset($installed[strtolower($package)])) { - continue; - } - - $inst_version = $reg->packageInfo($package, 'version', $channel); - $inst_state = $reg->packageInfo($package, 'release_state', $channel); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - PEAR::popErrorHandling(); - if (PEAR::isError($info)) { - continue; // no remote releases - } - - if (!isset($info['r'])) { - continue; - } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - // $info['r'] is sorted by version number - usort($info['r'], array($this, '_sortReleasesByVersionNumber')); - foreach ($info['r'] as $release) { - if ($inst_version && version_compare($release['v'], $inst_version, '<=')) { - // not newer than the one installed - break; - } - - // new version > installed version - if (!$pref_state) { - // every state is a good state - $found = true; - break; - } else { - $new_state = $release['s']; - // if new state >= installed state: go - if (in_array($new_state, $this->betterStates($inst_state, true))) { - $found = true; - break; - } else { - // only allow to lower the state of package, - // if new state >= preferred state: go - if (in_array($new_state, $this->betterStates($pref_state, true))) { - $found = true; - break; - } - } - } - } - - if (!$found) { - continue; - } - - $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . - $release['v'] . '.xml', false, false, $channel); - if (PEAR::isError($relinfo)) { - return $relinfo; - } - - $ret[$package] = array( - 'version' => $release['v'], - 'state' => $release['s'], - 'filesize' => $relinfo['f'], - ); - } - - return $ret; - } - - function packageInfo($base, $package, $channel = false) - { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($pinfo)) { - PEAR::popErrorHandling(); - return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' . - $pinfo->getMessage()); - } - - $releases = array(); - $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (!PEAR::isError($allreleases)) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } - - if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) { - $allreleases['r'] = array($allreleases['r']); - } - - $pf = new PEAR_PackageFile_v2; - foreach ($allreleases['r'] as $release) { - $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . - $release['v'] . '.txt', false, false, $channel); - if (PEAR::isError($ds)) { - continue; - } - - if (!isset($latest)) { - $latest = $release['v']; - } - - $pf->setDeps(unserialize($ds)); - $ds = $pf->getDeps(); - $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) - . '/' . $release['v'] . '.xml', false, false, $channel); - - if (PEAR::isError($info)) { - continue; - } - - $releases[$release['v']] = array( - 'doneby' => $info['m'], - 'license' => $info['l'], - 'summary' => $info['s'], - 'description' => $info['d'], - 'releasedate' => $info['da'], - 'releasenotes' => $info['n'], - 'state' => $release['s'], - 'deps' => $ds ? $ds : array(), - ); - } - } else { - $latest = ''; - } - - PEAR::popErrorHandling(); - if (isset($pinfo['dc']) && isset($pinfo['dp'])) { - if (is_array($pinfo['dp'])) { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp']['_content'])); - } else { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp'])); - } - } else { - $deprecated = false; - } - - if (!isset($latest)) { - $latest = ''; - } - - return array( - 'name' => $pinfo['n'], - 'channel' => $pinfo['c'], - 'category' => $pinfo['ca']['_content'], - 'stable' => $latest, - 'license' => $pinfo['l'], - 'summary' => $pinfo['s'], - 'description' => $pinfo['d'], - 'releases' => $releases, - 'deprecated' => $deprecated, - ); - } - - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - - if ($include) { - $i--; - } - - return array_slice($states, $i + 1); - } - - /** - * Sort releases by version number - * - * @access private - */ - function _sortReleasesByVersionNumber($a, $b) - { - if (version_compare($a['v'], $b['v'], '=')) { - return 0; - } - - if (version_compare($a['v'], $b['v'], '>')) { - return -1; - } - - if (version_compare($a['v'], $b['v'], '<')) { - return 1; - } - } -}PEAR-1.9.0/PEAR/REST/11.php100664 764 764 26054 100664 7573 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 11.php 286670 2009-08-02 14:16:06Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.3 - */ - -/** - * For downloading REST xml/txt files - */ -require_once 'PEAR/REST.php'; - -/** - * Implement REST 1.1 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.3 - */ -class PEAR_REST_11 -{ - /** - * @var PEAR_REST - */ - var $_rest; - - function PEAR_REST_11($config, $options = array()) - { - $this->_rest = &new PEAR_REST($config, $options); - } - - function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) - { - $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); - if (PEAR::isError($categorylist)) { - return $categorylist; - } - - $ret = array(); - if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) { - $categorylist['c'] = array($categorylist['c']); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - - foreach ($categorylist['c'] as $progress => $category) { - $category = $category['_content']; - $packagesinfo = $this->_rest->retrieveData($base . - 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel); - - if (PEAR::isError($packagesinfo)) { - continue; - } - - if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) { - continue; - } - - if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) { - $packagesinfo['pi'] = array($packagesinfo['pi']); - } - - foreach ($packagesinfo['pi'] as $packageinfo) { - if (empty($packageinfo)) { - continue; - } - - $info = $packageinfo['p']; - $package = $info['n']; - $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false; - unset($latest); - unset($unstable); - unset($stable); - unset($state); - - if ($releases) { - if (!isset($releases['r'][0])) { - $releases['r'] = array($releases['r']); - } - - foreach ($releases['r'] as $release) { - if (!isset($latest)) { - if ($dostable && $release['s'] == 'stable') { - $latest = $release['v']; - $state = 'stable'; - } - if (!$dostable) { - $latest = $release['v']; - $state = $release['s']; - } - } - - if (!isset($stable) && $release['s'] == 'stable') { - $stable = $release['v']; - if (!isset($unstable)) { - $unstable = $stable; - } - } - - if (!isset($unstable) && $release['s'] != 'stable') { - $unstable = $release['v']; - $state = $release['s']; - } - - if (isset($latest) && !isset($state)) { - $state = $release['s']; - } - - if (isset($latest) && isset($stable) && isset($unstable)) { - break; - } - } - } - - if ($basic) { // remote-list command - if (!isset($latest)) { - $latest = false; - } - - if ($dostable) { - // $state is not set if there are no releases - if (isset($state) && $state == 'stable') { - $ret[$package] = array('stable' => $latest); - } else { - $ret[$package] = array('stable' => '-n/a-'); - } - } else { - $ret[$package] = array('stable' => $latest); - } - - continue; - } - - // list-all command - if (!isset($unstable)) { - $unstable = false; - $state = 'stable'; - if (isset($stable)) { - $latest = $unstable = $stable; - } - } else { - $latest = $unstable; - } - - if (!isset($latest)) { - $latest = false; - } - - $deps = array(); - if ($latest && isset($packageinfo['deps'])) { - if (!is_array($packageinfo['deps']) || - !isset($packageinfo['deps'][0]) - ) { - $packageinfo['deps'] = array($packageinfo['deps']); - } - - $d = false; - foreach ($packageinfo['deps'] as $dep) { - if ($dep['v'] == $latest) { - $d = unserialize($dep['d']); - } - } - - if ($d) { - if (isset($d['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } - - if (!isset($pf)) { - $pf = new PEAR_PackageFile_v2; - } - - $pf->setDeps($d); - $tdeps = $pf->getDeps(); - } else { - $tdeps = $d; - } - - foreach ($tdeps as $dep) { - if ($dep['type'] !== 'pkg') { - continue; - } - - $deps[] = $dep; - } - } - } - - $info = array( - 'stable' => $latest, - 'summary' => $info['s'], - 'description' => $info['d'], - 'deps' => $deps, - 'category' => $info['ca']['_content'], - 'unstable' => $unstable, - 'state' => $state - ); - $ret[$package] = $info; - } - } - - PEAR::popErrorHandling(); - return $ret; - } - - /** - * List all categories of a REST server - * - * @param string $base base URL of the server - * @return array of categorynames - */ - function listCategories($base, $channel = false) - { - $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); - if (PEAR::isError($categorylist)) { - return $categorylist; - } - - if (!is_array($categorylist) || !isset($categorylist['c'])) { - return array(); - } - - if (isset($categorylist['c']['_content'])) { - // only 1 category - $categorylist['c'] = array($categorylist['c']); - } - - return $categorylist['c']; - } - - /** - * List packages in a category of a REST server - * - * @param string $base base URL of the server - * @param string $category name of the category - * @param boolean $info also download full package info - * @return array of packagenames - */ - function listCategory($base, $category, $info = false, $channel = false) - { - if ($info == false) { - $url = '%s'.'c/%s/packages.xml'; - } else { - $url = '%s'.'c/%s/packagesinfo.xml'; - } - $url = sprintf($url, - $base, - urlencode($category)); - - // gives '404 Not Found' error when category doesn't exist - $packagelist = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if (!is_array($packagelist)) { - return array(); - } - - if ($info == false) { - if (!isset($packagelist['p'])) { - return array(); - } - if (!is_array($packagelist['p']) || - !isset($packagelist['p'][0])) { // only 1 pkg - $packagelist = array($packagelist['p']); - } else { - $packagelist = $packagelist['p']; - } - return $packagelist; - } - - // info == true - if (!isset($packagelist['pi'])) { - return array(); - } - - if (!is_array($packagelist['pi']) || - !isset($packagelist['pi'][0])) { // only 1 pkg - $packagelist_pre = array($packagelist['pi']); - } else { - $packagelist_pre = $packagelist['pi']; - } - - $packagelist = array(); - foreach ($packagelist_pre as $i => $item) { - // compatibility with r/.xml - if (isset($item['a']['r'][0])) { - // multiple releases - $item['p']['v'] = $item['a']['r'][0]['v']; - $item['p']['st'] = $item['a']['r'][0]['s']; - } elseif (isset($item['a'])) { - // first and only release - $item['p']['v'] = $item['a']['r']['v']; - $item['p']['st'] = $item['a']['r']['s']; - } - - $packagelist[$i] = array('attribs' => $item['p']['r'], - '_content' => $item['p']['n'], - 'info' => $item['p']); - } - - return $packagelist; - } - - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - if ($include) { - $i--; - } - return array_slice($states, $i + 1); - } -} -?>PEAR-1.9.0/PEAR/REST/13.php100664 764 764 26544 100664 7601 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 13.php 287110 2009-08-11 18:51:15Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a12 - */ - -/** - * For downloading REST xml/txt files - */ -require_once 'PEAR/REST.php'; -require_once 'PEAR/REST/10.php'; - -/** - * Implement REST 1.3 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a12 - */ -class PEAR_REST_13 extends PEAR_REST_10 -{ - /** - * Retrieve information about a remote package to be downloaded from a REST server - * - * This is smart enough to resolve the minimum PHP version dependency prior to download - * @param string $base The uri to prepend to all REST calls - * @param array $packageinfo an array of format: - *
    -     *  array(
    -     *   'package' => 'packagename',
    -     *   'channel' => 'channelname',
    -     *  ['state' => 'alpha' (or valid state),]
    -     *  -or-
    -     *  ['version' => '1.whatever']
    -     * 
    - * @param string $prefstate Current preferred_state config variable value - * @param bool $installed the installed version of this package to compare against - * @return array|false|PEAR_Error see {@link _returnDownloadURL()} - */ - function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) - { - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $channel = $packageinfo['channel']; - $package = $packageinfo['package']; - $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; - $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; - $restFile = $base . 'r/' . strtolower($package) . '/allreleases2.xml'; - - $info = $this->_rest->retrieveData($restFile, false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('No releases available for package "' . - $channel . '/' . $package . '"'); - } - - if (!isset($info['r'])) { - return false; - } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - $skippedphp = false; - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - - if (isset($state)) { - // try our preferred state first - if ($release['s'] == $state) { - if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - - // see if there is something newer and more stable - // bug #7221 - if (in_array($release['s'], $this->betterStates($state), true)) { - if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - } elseif (isset($version)) { - if ($release['v'] == $version) { - if (!isset($this->_rest->_options['force']) && - !isset($version) && - version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - } else { - if (in_array($release['s'], $states)) { - if (version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - } - } - - if (!$found && $skippedphp) { - $found = null; - } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); - } - - function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, - $prefstate = 'stable', $installed = false, $channel = false) - { - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $channel = $dependency['channel']; - $package = $dependency['name']; - $state = isset($dependency['state']) ? $dependency['state'] : null; - $version = isset($dependency['version']) ? $dependency['version'] : null; - $restFile = $base . 'r/' . strtolower($package) .'/allreleases2.xml'; - - $info = $this->_rest->retrieveData($restFile, false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] - . '" dependency "' . $channel . '/' . $package . '" has no releases'); - } - - if (!is_array($info) || !isset($info['r'])) { - return false; - } - - $exclude = array(); - $min = $max = $recommended = false; - if ($xsdversion == '1.0') { - $pinfo['package'] = $dependency['name']; - $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this - switch ($dependency['rel']) { - case 'ge' : - $min = $dependency['version']; - break; - case 'gt' : - $min = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'eq' : - $recommended = $dependency['version']; - break; - case 'lt' : - $max = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'le' : - $max = $dependency['version']; - break; - case 'ne' : - $exclude = array($dependency['version']); - break; - } - } else { - $pinfo['package'] = $dependency['name']; - $min = isset($dependency['min']) ? $dependency['min'] : false; - $max = isset($dependency['max']) ? $dependency['max'] : false; - $recommended = isset($dependency['recommended']) ? - $dependency['recommended'] : false; - if (isset($dependency['exclude'])) { - if (!isset($dependency['exclude'][0])) { - $exclude = array($dependency['exclude']); - } - } - } - - $skippedphp = $found = $release = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - - if (in_array($release['v'], $exclude)) { // skip excluded versions - continue; - } - - // allow newer releases to say "I'm OK with the dependent package" - if ($xsdversion == '2.0' && isset($release['co'])) { - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - - foreach ($release['co'] as $entry) { - if (isset($entry['x']) && !is_array($entry['x'])) { - $entry['x'] = array($entry['x']); - } elseif (!isset($entry['x'])) { - $entry['x'] = array(); - } - - if ($entry['c'] == $deppackage['channel'] && - strtolower($entry['p']) == strtolower($deppackage['package']) && - version_compare($deppackage['version'], $entry['min'], '>=') && - version_compare($deppackage['version'], $entry['max'], '<=') && - !in_array($release['v'], $entry['x'])) { - if (version_compare($release['m'], phpversion(), '>')) { - // skip dependency releases that require a PHP version - // newer than our PHP version - $skippedphp = $release; - continue; - } - - $recommended = $release['v']; - break; - } - } - } - - if ($recommended) { - if ($release['v'] != $recommended) { // if we want a specific - // version, then skip all others - continue; - } - - if (!in_array($release['s'], $states)) { - // the stability is too low, but we must return the - // recommended version if possible - return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); - } - } - - if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions - continue; - } - - if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions - continue; - } - - if ($installed && version_compare($release['v'], $installed, '<')) { - continue; - } - - if (in_array($release['s'], $states)) { // if in the preferred state... - if (version_compare($release['m'], phpversion(), '>')) { - // skip dependency releases that require a PHP version - // newer than our PHP version - $skippedphp = $release; - continue; - } - - $found = true; // ... then use it - break; - } - } - - if (!$found && $skippedphp) { - $found = null; - } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); - } -}PEAR-1.9.0/PEAR/Task/Postinstallscript/rw.php100664 764 764 13311 100664 13660 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Postinstallscript.php'; -/** - * Abstracts the postinstallscript file task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript -{ - /** - * parent package file object - * - * @var PEAR_PackageFile_v2_rw - */ - var $_pkg; - /** - * Enter description here... - * - * @param PEAR_PackageFile_v2_rw $pkg - * @param PEAR_Config $config - * @param PEAR_Frontend $logger - * @param array $fileXml - * @return PEAR_Task_Postinstallscript_rw - */ - function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); - } - - function getName() - { - return 'postinstallscript'; - } - - /** - * add a simple to the post-install script - * - * Order is significant, so call this method in the same - * sequence the users should see the paramgroups. The $params - * parameter should either be the result of a call to {@link getParam()} - * or an array of calls to getParam(). - * - * Use {@link addConditionTypeGroup()} to add a containing - * a tag - * @param string $id id as seen by the script - * @param array|false $params array of getParam() calls, or false for no params - * @param string|false $instructions - */ - function addParamGroup($id, $params = false, $instructions = false) - { - if ($params && isset($params[0]) && !isset($params[1])) { - $params = $params[0]; - } - $stuff = - array( - $this->_pkg->getTasksNs() . ':id' => $id, - ); - if ($instructions) { - $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; - } - if ($params) { - $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; - } - $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; - } - - /** - * add a complex to the post-install script with conditions - * - * This inserts a with - * - * Order is significant, so call this method in the same - * sequence the users should see the paramgroups. The $params - * parameter should either be the result of a call to {@link getParam()} - * or an array of calls to getParam(). - * - * Use {@link addParamGroup()} to add a simple - * - * @param string $id id as seen by the script - * @param string $oldgroup id of the section referenced by - * - * @param string $param name of the from the older section referenced - * by - * @param string $value value to match of the parameter - * @param string $conditiontype one of '=', '!=', 'preg_match' - * @param array|false $params array of getParam() calls, or false for no params - * @param string|false $instructions - */ - function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=', - $params = false, $instructions = false) - { - if ($params && isset($params[0]) && !isset($params[1])) { - $params = $params[0]; - } - $stuff = array( - $this->_pkg->getTasksNs() . ':id' => $id, - ); - if ($instructions) { - $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; - } - $stuff[$this->_pkg->getTasksNs() . ':name'] = $oldgroup . '::' . $param; - $stuff[$this->_pkg->getTasksNs() . ':conditiontype'] = $conditiontype; - $stuff[$this->_pkg->getTasksNs() . ':value'] = $value; - if ($params) { - $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; - } - $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; - } - - function getXml() - { - return $this->_params; - } - - /** - * Use to set up a param tag for use in creating a paramgroup - * @static - */ - function getParam($name, $prompt, $type = 'string', $default = null) - { - if ($default !== null) { - return - array( - $this->_pkg->getTasksNs() . ':name' => $name, - $this->_pkg->getTasksNs() . ':prompt' => $prompt, - $this->_pkg->getTasksNs() . ':type' => $type, - $this->_pkg->getTasksNs() . ':default' => $default - ); - } - return - array( - $this->_pkg->getTasksNs() . ':name' => $name, - $this->_pkg->getTasksNs() . ':prompt' => $prompt, - $this->_pkg->getTasksNs() . ':type' => $type, - ); - } -} -?>PEAR-1.9.0/PEAR/Task/Replace/rw.php100664 764 764 3115 100664 11453 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Replace.php'; -/** - * Abstracts the replace task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Replace_rw extends PEAR_Task_Replace -{ - function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); - } - - function setInfo($from, $to, $type) - { - $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); - } - - function getName() - { - return 'replace'; - } - - function getXml() - { - return $this->_params; - } -} -?>PEAR-1.9.0/PEAR/Task/Unixeol/rw.php100664 764 764 2535 100664 11530 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Unixeol.php'; -/** - * Abstracts the unixeol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol -{ - function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'unixeol'; - } - - function getXml() - { - return ''; - } -} -?>PEAR-1.9.0/PEAR/Task/Windowseol/rw.php100664 764 764 2562 100664 12237 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Windowseol.php'; -/** - * Abstracts the windowseol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol -{ - function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'windowseol'; - } - - function getXml() - { - return ''; - } -} -?>PEAR-1.9.0/PEAR/Task/Common.php100664 764 764 13736 100664 10732 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/**#@+ - * Error codes for task validation routines - */ -define('PEAR_TASK_ERROR_NOATTRIBS', 1); -define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2); -define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3); -define('PEAR_TASK_ERROR_INVALID', 4); -/**#@-*/ -define('PEAR_TASK_PACKAGE', 1); -define('PEAR_TASK_INSTALL', 2); -define('PEAR_TASK_PACKAGEANDINSTALL', 3); -/** - * A task is an operation that manipulates the contents of a file. - * - * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been - * processed and installed, and are designed to operate on all files containing the task. - * The Post-install script task simply takes advantage of the fact that it will be run - * after installation, replace is a simple task. - * - * Combining tasks is possible, but ordering is significant. - * - * - * - * - * - * - * This will first replace any instance of @data-dir@ in the test.php file - * with the path to the current data directory. Then, it will include the - * test.php file and run the script it contains to configure the package post-installation. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - * @abstract - */ -class PEAR_Task_Common -{ - /** - * Valid types for this version are 'simple' and 'multiple' - * - * - simple tasks operate on the contents of a file and write out changes to disk - * - multiple tasks operate on the contents of many files and write out the - * changes directly to disk - * - * Child task classes must override this property. - * @access protected - */ - var $type = 'simple'; - /** - * Determines which install phase this task is executed under - */ - var $phase = PEAR_TASK_INSTALL; - /** - * @access protected - */ - var $config; - /** - * @access protected - */ - var $registry; - /** - * @access protected - */ - var $logger; - /** - * @access protected - */ - var $installphase; - /** - * @param PEAR_Config - * @param PEAR_Common - */ - function PEAR_Task_Common(&$config, &$logger, $phase) - { - $this->config = &$config; - $this->registry = &$config->getRegistry(); - $this->logger = &$logger; - $this->installphase = $phase; - if ($this->type == 'multiple') { - $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this; - } - } - - /** - * Validate the basic contents of a task tag. - * @param PEAR_PackageFile_v2 - * @param array - * @param PEAR_Config - * @param array the entire parsed tag - * @return true|array On error, return an array in format: - * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...]) - * - * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in - * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array - * of legal values in - * @static - * @abstract - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param array attributes from the tag containing this task - * @param string|null last installed version of this package - * @abstract - */ - function init($xml, $fileAttributes, $lastVersion) - { - } - - /** - * Begin a task processing session. All multiple tasks will be processed after each file - * has been successfully installed, all simple tasks should perform their task here and - * return any errors using the custom throwError() method to allow forward compatibility - * - * This method MUST NOT write out any changes to disk - * @param PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - * @abstract - */ - function startSession($pkg, $contents, $dest) - { - } - - /** - * This method is used to process each of the tasks for a particular multiple class - * type. Simple tasks need not implement this method. - * @param array an array of tasks - * @access protected - * @static - * @abstract - */ - function run($tasks) - { - } - - /** - * @static - * @final - */ - function hasPostinstallTasks() - { - return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); - } - - /** - * @static - * @final - */ - function runPostinstallTasks() - { - foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) { - $err = call_user_func(array($class, 'run'), - $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]); - if ($err) { - return PEAR_Task_Common::throwError($err); - } - } - unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); - } - - /** - * Determines whether a role is a script - * @return bool - */ - function isScript() - { - return $this->type == 'script'; - } - - function throwError($msg, $code = -1) - { - include_once 'PEAR.php'; - return PEAR::raiseError($msg, $code); - } -} -?>PEAR-1.9.0/PEAR/Task/Postinstallscript.php100664 764 764 34122 100664 13233 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Postinstallscript.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the postinstallscript file task. - * - * Note that post-install scripts are handled separately from installation, by the - * "pear run-scripts" command - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Postinstallscript extends PEAR_Task_Common -{ - var $type = 'script'; - var $_class; - var $_params; - var $_obj; - /** - * - * @var PEAR_PackageFile_v2 - */ - var $_pkg; - var $_contents; - var $phase = PEAR_TASK_INSTALL; - - /** - * Validate the raw xml at parsing-time. - * - * This also attempts to validate the script to make sure it meets the criteria - * for a post-install script - * @param PEAR_PackageFile_v2 - * @param array The XML contents of the tag - * @param PEAR_Config - * @param array the entire parsed tag - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($fileXml['role'] != 'php') { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must be role="php"'); - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $file = $pkg->getFileContents($fileXml['name']); - if (PEAR::isError($file)) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" is not valid: ' . - $file->getMessage()); - } elseif ($file === null) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" could not be retrieved for processing!'); - } else { - $analysis = $pkg->analyzeSourceCode($file, true); - if (!$analysis) { - PEAR::popErrorHandling(); - $warnings = ''; - foreach ($pkg->getValidationWarnings() as $warn) { - $warnings .= $warn['message'] . "\n"; - } - return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' . - $fileXml['name'] . '" failed: ' . $warnings); - } - if (count($analysis['declared_classes']) != 1) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare exactly 1 class'); - } - $class = $analysis['declared_classes'][0]; - if ($class != str_replace(array('/', '.php'), array('_', ''), - $fileXml['name']) . '_postinstall') { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" class "' . $class . '" must be named "' . - str_replace(array('/', '.php'), array('_', ''), - $fileXml['name']) . '_postinstall"'); - } - if (!isset($analysis['declared_methods'][$class])) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare methods init() and run()'); - } - $methods = array('init' => 0, 'run' => 1); - foreach ($analysis['declared_methods'][$class] as $method) { - if (isset($methods[$method])) { - unset($methods[$method]); - } - } - if (count($methods)) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare methods init() and run()'); - } - } - PEAR::popErrorHandling(); - $definedparams = array(); - $tasksNamespace = $pkg->getTasksNs() . ':'; - if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) { - // in order to support the older betas, which did not expect internal tags - // to also use the namespace - $tasksNamespace = ''; - } - if (isset($xml[$tasksNamespace . 'paramgroup'])) { - $params = $xml[$tasksNamespace . 'paramgroup']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); - } - foreach ($params as $param) { - if (!isset($param[$tasksNamespace . 'id'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must have ' . - 'an ' . $tasksNamespace . 'id> tag'); - } - if (isset($param[$tasksNamespace . 'name'])) { - if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" parameter "' . $param[$tasksNamespace . 'name'] . - '" has not been previously defined'); - } - if (!isset($param[$tasksNamespace . 'conditiontype'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'conditiontype> tag containing either "=", ' . - '"!=", or "preg_match"'); - } - if (!in_array($param[$tasksNamespace . 'conditiontype'], - array('=', '!=', 'preg_match'))) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'conditiontype> tag containing either "=", ' . - '"!=", or "preg_match"'); - } - if (!isset($param[$tasksNamespace . 'value'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'value> tag containing expected parameter value'); - } - } - if (isset($param[$tasksNamespace . 'instructions'])) { - if (!is_string($param[$tasksNamespace . 'instructions'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" ' . $tasksNamespace . 'instructions> must be simple text'); - } - } - if (!isset($param[$tasksNamespace . 'param'])) { - continue; // is no longer required - } - $subparams = $param[$tasksNamespace . 'param']; - if (!is_array($subparams) || !isset($subparams[0])) { - $subparams = array($subparams); - } - foreach ($subparams as $subparam) { - if (!isset($subparam[$tasksNamespace . 'name'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter for ' . - $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . '" must have ' . - 'a ' . $tasksNamespace . 'name> tag'); - } - if (!preg_match('/[a-zA-Z0-9]+/', - $subparam[$tasksNamespace . 'name'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" is not a valid name. Must contain only alphanumeric characters'); - } - if (!isset($subparam[$tasksNamespace . 'prompt'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . 'prompt> tag'); - } - if (!isset($subparam[$tasksNamespace . 'type'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . 'type> tag'); - } - $definedparams[] = $param[$tasksNamespace . 'id'] . '::' . - $subparam[$tasksNamespace . 'name']; - } - } - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param array attributes from the tag containing this task - * @param string|null last installed version of this package, if any (useful for upgrades) - */ - function init($xml, $fileattribs, $lastversion) - { - $this->_class = str_replace('/', '_', $fileattribs['name']); - $this->_filename = $fileattribs['name']; - $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall'; - $this->_params = $xml; - $this->_lastversion = $lastversion; - } - - /** - * Strip the tasks: namespace from internal params - * - * @access private - */ - function _stripNamespace($params = null) - { - if ($params === null) { - $params = array(); - if (!is_array($this->_params)) { - return; - } - foreach ($this->_params as $i => $param) { - if (is_array($param)) { - $param = $this->_stripNamespace($param); - } - $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; - } - $this->_params = $params; - } else { - $newparams = array(); - foreach ($params as $i => $param) { - if (is_array($param)) { - $param = $this->_stripNamespace($param); - } - $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; - } - return $newparams; - } - } - - /** - * Unlike other tasks, the installed file name is passed in instead of the file contents, - * because this task is handled post-installation - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file name - * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError) - */ - function startSession($pkg, $contents) - { - if ($this->installphase != PEAR_TASK_INSTALL) { - return false; - } - // remove the tasks: namespace if present - $this->_pkg = $pkg; - $this->_stripNamespace(); - $this->logger->log(0, 'Including external post-installation script "' . - $contents . '" - any errors are in this script'); - include_once $contents; - if (class_exists($this->_class)) { - $this->logger->log(0, 'Inclusion succeeded'); - } else { - return $this->throwError('init of post-install script class "' . $this->_class - . '" failed'); - } - $this->_obj = new $this->_class; - $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $res = $this->_obj->init($this->config, $pkg, $this->_lastversion); - PEAR::popErrorHandling(); - if ($res) { - $this->logger->log(0, 'init succeeded'); - } else { - return $this->throwError('init of post-install script "' . $this->_class . - '->init()" failed'); - } - $this->_contents = $contents; - return true; - } - - /** - * No longer used - * @see PEAR_PackageFile_v2::runPostinstallScripts() - * @param array an array of tasks - * @param string install or upgrade - * @access protected - * @static - */ - function run() - { - } -} -?>PEAR-1.9.0/PEAR/Task/Replace.php100664 764 764 15232 100664 11046 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Replace.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the replace file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Replace extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGEANDINSTALL; - var $_replacements; - - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if (!isset($xml['attribs'])) { - return array(PEAR_TASK_ERROR_NOATTRIBS); - } - if (!isset($xml['attribs']['type'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type'); - } - if (!isset($xml['attribs']['to'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to'); - } - if (!isset($xml['attribs']['from'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from'); - } - if ($xml['attribs']['type'] == 'pear-config') { - if (!in_array($xml['attribs']['to'], $config->getKeys())) { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - $config->getKeys()); - } - } elseif ($xml['attribs']['type'] == 'php-const') { - if (defined($xml['attribs']['to'])) { - return true; - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - array('valid PHP constant')); - } - } elseif ($xml['attribs']['type'] == 'package-info') { - if (in_array($xml['attribs']['to'], - array('name', 'summary', 'channel', 'notes', 'extends', 'description', - 'release_notes', 'license', 'release-license', 'license-uri', - 'version', 'api-version', 'state', 'api-state', 'release_date', - 'date', 'time'))) { - return true; - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - array('name', 'summary', 'channel', 'notes', 'extends', 'description', - 'release_notes', 'license', 'release-license', 'license-uri', - 'version', 'api-version', 'state', 'api-state', 'release_date', - 'date', 'time')); - } - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'], - array('pear-config', 'package-info', 'php-const')); - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) - { - $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml; - } - - /** - * Do a package.xml 1.0 replacement, with additional package-info fields available - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) - { - $subst_from = $subst_to = array(); - foreach ($this->_replacements as $a) { - $a = $a['attribs']; - $to = ''; - if ($a['type'] == 'pear-config') { - if ($this->installphase == PEAR_TASK_PACKAGE) { - return false; - } - if ($a['to'] == 'master_server') { - $chan = $this->registry->getChannel($pkg->getChannel()); - if (!PEAR::isError($chan)) { - $to = $chan->getServer(); - } else { - $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); - return false; - } - } else { - if ($this->config->isDefinedLayer('ftp')) { - // try the remote config file first - $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel()); - if (is_null($to)) { - // then default to local - $to = $this->config->get($a['to'], null, $pkg->getChannel()); - } - } else { - $to = $this->config->get($a['to'], null, $pkg->getChannel()); - } - } - if (is_null($to)) { - $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); - return false; - } - } elseif ($a['type'] == 'php-const') { - if ($this->installphase == PEAR_TASK_PACKAGE) { - return false; - } - if (defined($a['to'])) { - $to = constant($a['to']); - } else { - $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]"); - return false; - } - } else { - if ($t = $pkg->packageInfo($a['to'])) { - $to = $t; - } else { - $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]"); - return false; - } - } - if (!is_null($to)) { - $subst_from[] = $a['from']; - $subst_to[] = $to; - } - } - $this->logger->log(3, "doing " . sizeof($subst_from) . - " substitution(s) for $dest"); - if (sizeof($subst_from)) { - $contents = str_replace($subst_from, $subst_to, $contents); - } - return $contents; - } -} -?>PEAR-1.9.0/PEAR/Task/Unixeol.php100664 764 764 4341 100664 11075 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Unixeol.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the unix line endings file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Unixeol extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGE; - var $_replacements; - - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($xml != '') { - return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) - { - } - - /** - * Replace all line endings with line endings customized for the current OS - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) - { - $this->logger->log(3, "replacing all line endings with \\n in $dest"); - return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); - } -} -?>PEAR-1.9.0/PEAR/Task/Windowseol.php100664 764 764 4335 100664 11607 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Windowseol.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the windows line endsings file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Windowseol extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGE; - var $_replacements; - - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($xml != '') { - return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) - { - } - - /** - * Replace all line endings with windows line endings - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) - { - $this->logger->log(3, "replacing all line endings with \\r\\n in $dest"); - return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); - } -} -?>PEAR-1.9.0/PEAR/Validator/PECL.php100664 764 764 4175 100664 11225 - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PECL.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a5 - */ -/** - * This is the parent class for all validators - */ -require_once 'PEAR/Validate.php'; -/** - * Channel Validator for the pecl.php.net channel - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a5 - */ -class PEAR_Validator_PECL extends PEAR_Validate -{ - function validateVersion() - { - if ($this->_state == PEAR_VALIDATE_PACKAGING) { - $version = $this->_packagexml->getVersion(); - $versioncomponents = explode('.', $version); - $last = array_pop($versioncomponents); - if (substr($last, 1, 2) == 'rc') { - $this->_addFailure('version', 'Release Candidate versions must have ' . - 'upper-case RC, not lower-case rc'); - return false; - } - } - return true; - } - - function validatePackageName() - { - $ret = parent::validatePackageName(); - if ($this->_packagexml->getPackageType() == 'extsrc' || - $this->_packagexml->getPackageType() == 'zendextsrc') { - if (strtolower($this->_packagexml->getPackage()) != - strtolower($this->_packagexml->getProvidesExtension())) { - $this->_addWarning('providesextension', 'package name "' . - $this->_packagexml->getPackage() . '" is different from extension name "' . - $this->_packagexml->getProvidesExtension() . '"'); - } - } - return $ret; - } -} -?>PEAR-1.9.0/PEAR/Autoloader.php100664 764 764 14645 100664 10677 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Autoloader.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader - * @since File available since Release 0.1 - * @deprecated File deprecated in Release 1.4.0a1 - */ - -// /* vim: set expandtab tabstop=4 shiftwidth=4: */ - -if (!extension_loaded("overload")) { - // die hard without ext/overload - die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader"); -} - -/** - * Include for PEAR_Error and PEAR classes - */ -require_once "PEAR.php"; - -/** - * This class is for objects where you want to separate the code for - * some methods into separate classes. This is useful if you have a - * class with not-frequently-used methods that contain lots of code - * that you would like to avoid always parsing. - * - * The PEAR_Autoloader class provides autoloading and aggregation. - * The autoloading lets you set up in which classes the separated - * methods are found. Aggregation is the technique used to import new - * methods, an instance of each class providing separated methods is - * stored and called every time the aggregated method is called. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader - * @since File available since Release 0.1 - * @deprecated File deprecated in Release 1.4.0a1 - */ -class PEAR_Autoloader extends PEAR -{ - // {{{ properties - - /** - * Map of methods and classes where they are defined - * - * @var array - * - * @access private - */ - var $_autoload_map = array(); - - /** - * Map of methods and aggregate objects - * - * @var array - * - * @access private - */ - var $_method_map = array(); - - // }}} - // {{{ addAutoload() - - /** - * Add one or more autoload entries. - * - * @param string $method which method to autoload - * - * @param string $classname (optional) which class to find the method in. - * If the $method parameter is an array, this - * parameter may be omitted (and will be ignored - * if not), and the $method parameter will be - * treated as an associative array with method - * names as keys and class names as values. - * - * @return void - * - * @access public - */ - function addAutoload($method, $classname = null) - { - if (is_array($method)) { - array_walk($method, create_function('$a,&$b', '$b = strtolower($b);')); - $this->_autoload_map = array_merge($this->_autoload_map, $method); - } else { - $this->_autoload_map[strtolower($method)] = $classname; - } - } - - // }}} - // {{{ removeAutoload() - - /** - * Remove an autoload entry. - * - * @param string $method which method to remove the autoload entry for - * - * @return bool TRUE if an entry was removed, FALSE if not - * - * @access public - */ - function removeAutoload($method) - { - $method = strtolower($method); - $ok = isset($this->_autoload_map[$method]); - unset($this->_autoload_map[$method]); - return $ok; - } - - // }}} - // {{{ addAggregateObject() - - /** - * Add an aggregate object to this object. If the specified class - * is not defined, loading it will be attempted following PEAR's - * file naming scheme. All the methods in the class will be - * aggregated, except private ones (name starting with an - * underscore) and constructors. - * - * @param string $classname what class to instantiate for the object. - * - * @return void - * - * @access public - */ - function addAggregateObject($classname) - { - $classname = strtolower($classname); - if (!class_exists($classname)) { - $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); - include_once $include_file; - } - $obj =& new $classname; - $methods = get_class_methods($classname); - foreach ($methods as $method) { - // don't import priviate methods and constructors - if ($method{0} != '_' && $method != $classname) { - $this->_method_map[$method] = $obj; - } - } - } - - // }}} - // {{{ removeAggregateObject() - - /** - * Remove an aggregate object. - * - * @param string $classname the class of the object to remove - * - * @return bool TRUE if an object was removed, FALSE if not - * - * @access public - */ - function removeAggregateObject($classname) - { - $ok = false; - $classname = strtolower($classname); - reset($this->_method_map); - while (list($method, $obj) = each($this->_method_map)) { - if (is_a($obj, $classname)) { - unset($this->_method_map[$method]); - $ok = true; - } - } - return $ok; - } - - // }}} - // {{{ __call() - - /** - * Overloaded object call handler, called each time an - * undefined/aggregated method is invoked. This method repeats - * the call in the right aggregate object and passes on the return - * value. - * - * @param string $method which method that was called - * - * @param string $args An array of the parameters passed in the - * original call - * - * @return mixed The return value from the aggregated method, or a PEAR - * error if the called method was unknown. - */ - function __call($method, $args, &$retval) - { - $method = strtolower($method); - if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { - $this->addAggregateObject($this->_autoload_map[$method]); - } - if (isset($this->_method_map[$method])) { - $retval = call_user_func_array(array($this->_method_map[$method], $method), $args); - return true; - } - return false; - } - - // }}} -} - -overload("PEAR_Autoloader"); - -?> -PEAR-1.9.0/PEAR/Builder.php100664 764 764 40120 100664 10151 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Builder.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - * - * TODO: log output parameters in PECL command line - * TODO: msdev path in configuration - */ - -/** - * Needed for extending PEAR_Builder - */ -require_once 'PEAR/Common.php'; -require_once 'PEAR/PackageFile.php'; - -/** - * Class to handle building (compiling) extensions. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since PHP 4.0.2 - * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php - */ -class PEAR_Builder extends PEAR_Common -{ - var $php_api_version = 0; - var $zend_module_api_no = 0; - var $zend_extension_api_no = 0; - - var $extensions_built = array(); - - /** - * @var string Used for reporting when it is not possible to pass function - * via extra parameter, e.g. log, msdevCallback - */ - var $current_callback = null; - - // used for msdev builds - var $_lastline = null; - var $_firstline = null; - - /** - * PEAR_Builder constructor. - * - * @param object $ui user interface object (instance of PEAR_Frontend_*) - * - * @access public - */ - function PEAR_Builder(&$ui) - { - parent::PEAR_Common(); - $this->setFrontendObject($ui); - } - - /** - * Build an extension from source on windows. - * requires msdev - */ - function _build_win32($descfile, $callback = null) - { - if (is_object($descfile)) { - $pkg = $descfile; - $descfile = $pkg->getPackageFile(); - } else { - $pf = &new PEAR_PackageFile($this->config, $this->debug); - $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pkg)) { - return $pkg; - } - } - $dir = dirname($descfile); - $old_cwd = getcwd(); - - if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { - return $this->raiseError("could not chdir to $dir"); - } - - // packages that were in a .tar have the packagefile in this directory - $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); - if (file_exists($dir) && is_dir($vdir)) { - if (!chdir($vdir)) { - return $this->raiseError("could not chdir to " . realpath($vdir)); - } - - $dir = getcwd(); - } - - $this->log(2, "building in $dir"); - - $dsp = $pkg->getPackage().'.dsp'; - if (!file_exists("$dir/$dsp")) { - return $this->raiseError("The DSP $dsp does not exist."); - } - // XXX TODO: make release build type configurable - $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"'; - - $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); - if (PEAR::isError($err)) { - return $err; - } - - // figure out the build platform and type - $platform = 'Win32'; - $buildtype = 'Release'; - if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { - $platform = $matches[1]; - $buildtype = $matches[2]; - } - - if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/', $this->_lastline, $matches)) { - if ($matches[2]) { - // there were errors in the build - return $this->raiseError("There were errors during compilation."); - } - $out = $matches[1]; - } else { - return $this->raiseError("Did not understand the completion status returned from msdev.exe."); - } - - // msdev doesn't tell us the output directory :/ - // open the dsp, find /out and use that directory - $dsptext = join(file($dsp),''); - - // this regex depends on the build platform and type having been - // correctly identified above. - $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. - $pkg->getPackage().'\s-\s'. - $platform.'\s'. - $buildtype.'").*?'. - '\/out:"(.*?)"/is'; - - if ($dsptext && preg_match($regex, $dsptext, $matches)) { - // what we get back is a relative path to the output file itself. - $outfile = realpath($matches[2]); - } else { - return $this->raiseError("Could not retrieve output information from $dsp."); - } - // realpath returns false if the file doesn't exist - if ($outfile && copy($outfile, "$dir/$out")) { - $outfile = "$dir/$out"; - } - - $built_files[] = array( - 'file' => "$outfile", - 'php_api' => $this->php_api_version, - 'zend_mod_api' => $this->zend_module_api_no, - 'zend_ext_api' => $this->zend_extension_api_no, - ); - - return $built_files; - } - // }}} - - // {{{ msdevCallback() - function msdevCallback($what, $data) - { - if (!$this->_firstline) - $this->_firstline = $data; - $this->_lastline = $data; - call_user_func($this->current_callback, $what, $data); - } - - /** - * @param string - * @param string - * @param array - * @access private - */ - function _harvestInstDir($dest_prefix, $dirname, &$built_files) - { - $d = opendir($dirname); - if (!$d) - return false; - - $ret = true; - while (($ent = readdir($d)) !== false) { - if ($ent{0} == '.') - continue; - - $full = $dirname . DIRECTORY_SEPARATOR . $ent; - if (is_dir($full)) { - if (!$this->_harvestInstDir( - $dest_prefix . DIRECTORY_SEPARATOR . $ent, - $full, $built_files)) { - $ret = false; - break; - } - } else { - $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; - $built_files[] = array( - 'file' => $full, - 'dest' => $dest, - 'php_api' => $this->php_api_version, - 'zend_mod_api' => $this->zend_module_api_no, - 'zend_ext_api' => $this->zend_extension_api_no, - ); - } - } - closedir($d); - return $ret; - } - - /** - * Build an extension from source. Runs "phpize" in the source - * directory, but compiles in a temporary directory - * (/var/tmp/pear-build-USER/PACKAGE-VERSION). - * - * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or - * a PEAR_PackageFile object - * - * @param mixed $callback callback function used to report output, - * see PEAR_Builder::_runCommand for details - * - * @return array an array of associative arrays with built files, - * format: - * array( array( 'file' => '/path/to/ext.so', - * 'php_api' => YYYYMMDD, - * 'zend_mod_api' => YYYYMMDD, - * 'zend_ext_api' => YYYYMMDD ), - * ... ) - * - * @access public - * - * @see PEAR_Builder::_runCommand - */ - function build($descfile, $callback = null) - { - if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php(.+)?$/', - $this->config->get('php_bin'), $matches)) { - if (isset($matches[2]) && strlen($matches[2]) && - trim($matches[2]) != trim($this->config->get('php_prefix'))) { - $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . - ' appears to have a prefix ' . $matches[2] . ', but' . - ' config variable php_prefix does not match'); - } - if (isset($matches[3]) && strlen($matches[3]) && - trim($matches[3]) != trim($this->config->get('php_suffix'))) { - $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . - ' appears to have a suffix ' . $matches[3] . ', but' . - ' config variable php_suffix does not match'); - } - } - - - $this->current_callback = $callback; - if (PEAR_OS == "Windows") { - return $this->_build_win32($descfile, $callback); - } - if (PEAR_OS != 'Unix') { - return $this->raiseError("building extensions not supported on this platform"); - } - if (is_object($descfile)) { - $pkg = $descfile; - $descfile = $pkg->getPackageFile(); - if (is_a($pkg, 'PEAR_PackageFile_v1')) { - $dir = dirname($descfile); - } else { - $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName(); - // automatically delete at session end - $this->addTempFile($dir); - } - } else { - $pf = &new PEAR_PackageFile($this->config); - $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pkg)) { - return $pkg; - } - $dir = dirname($descfile); - } - $old_cwd = getcwd(); - if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { - return $this->raiseError("could not chdir to $dir"); - } - $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); - if (is_dir($vdir)) { - chdir($vdir); - } - $dir = getcwd(); - $this->log(2, "building in $dir"); - putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); - $err = $this->_runCommand($this->config->get('php_prefix') - . "phpize" . - $this->config->get('php_suffix'), - array(&$this, 'phpizeCallback')); - if (PEAR::isError($err)) { - return $err; - } - if (!$err) { - return $this->raiseError("`phpize' failed"); - } - - // {{{ start of interactive part - $configure_command = "$dir/configure"; - $configure_options = $pkg->getConfigureOptions(); - if ($configure_options) { - foreach ($configure_options as $o) { - $default = array_key_exists('default', $o) ? $o['default'] : null; - list($r) = $this->ui->userDialog('build', - array($o['prompt']), - array('text'), - array($default)); - if (substr($o['name'], 0, 5) == 'with-' && - ($r == 'yes' || $r == 'autodetect')) { - $configure_command .= " --$o[name]"; - } else { - $configure_command .= " --$o[name]=".trim($r); - } - } - } - // }}} end of interactive part - - // FIXME make configurable - if(!$user=getenv('USER')){ - $user='defaultuser'; - } - $build_basedir = "/var/tmp/pear-build-$user"; - $build_dir = "$build_basedir/$vdir"; - $inst_dir = "$build_basedir/install-$vdir"; - $this->log(1, "building in $build_dir"); - if (is_dir($build_dir)) { - System::rm(array('-rf', $build_dir)); - } - if (!System::mkDir(array('-p', $build_dir))) { - return $this->raiseError("could not create build dir: $build_dir"); - } - $this->addTempFile($build_dir); - if (!System::mkDir(array('-p', $inst_dir))) { - return $this->raiseError("could not create temporary install dir: $inst_dir"); - } - $this->addTempFile($inst_dir); - - if (getenv('MAKE')) { - $make_command = getenv('MAKE'); - } else { - $make_command = 'make'; - } - $to_run = array( - $configure_command, - $make_command, - "$make_command INSTALL_ROOT=\"$inst_dir\" install", - "find \"$inst_dir\" | xargs ls -dils" - ); - if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) { - return $this->raiseError("could not chdir to $build_dir"); - } - putenv('PHP_PEAR_VERSION=1.9.0'); - foreach ($to_run as $cmd) { - $err = $this->_runCommand($cmd, $callback); - if (PEAR::isError($err)) { - chdir($old_cwd); - return $err; - } - if (!$err) { - chdir($old_cwd); - return $this->raiseError("`$cmd' failed"); - } - } - if (!($dp = opendir("modules"))) { - chdir($old_cwd); - return $this->raiseError("no `modules' directory found"); - } - $built_files = array(); - $prefix = exec($this->config->get('php_prefix') - . "php-config" . - $this->config->get('php_suffix') . " --prefix"); - $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); - chdir($old_cwd); - return $built_files; - } - - /** - * Message callback function used when running the "phpize" - * program. Extracts the API numbers used. Ignores other message - * types than "cmdoutput". - * - * @param string $what the type of message - * @param mixed $data the message - * - * @return void - * - * @access public - */ - function phpizeCallback($what, $data) - { - if ($what != 'cmdoutput') { - return; - } - $this->log(1, rtrim($data)); - if (preg_match('/You should update your .aclocal.m4/', $data)) { - return; - } - $matches = array(); - if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { - $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); - $apino = (int)$matches[2]; - if (isset($this->$member)) { - $this->$member = $apino; - //$msg = sprintf("%-22s : %d", $matches[1], $apino); - //$this->log(1, $msg); - } - } - } - - /** - * Run an external command, using a message callback to report - * output. The command will be run through popen and output is - * reported for every line with a "cmdoutput" message with the - * line string, including newlines, as payload. - * - * @param string $command the command to run - * - * @param mixed $callback (optional) function to use as message - * callback - * - * @return bool whether the command was successful (exit code 0 - * means success, any other means failure) - * - * @access private - */ - function _runCommand($command, $callback = null) - { - $this->log(1, "running: $command"); - $pp = popen("$command 2>&1", "r"); - if (!$pp) { - return $this->raiseError("failed to run `$command'"); - } - if ($callback && $callback[0]->debug == 1) { - $olddbg = $callback[0]->debug; - $callback[0]->debug = 2; - } - - while ($line = fgets($pp, 1024)) { - if ($callback) { - call_user_func($callback, 'cmdoutput', $line); - } else { - $this->log(2, rtrim($line)); - } - } - if ($callback && isset($olddbg)) { - $callback[0]->debug = $olddbg; - } - - $exitcode = is_resource($pp) ? pclose($pp) : -1; - return ($exitcode == 0); - } - - function log($level, $msg) - { - if ($this->current_callback) { - if ($this->debug >= $level) { - call_user_func($this->current_callback, 'output', $msg); - } - return; - } - return PEAR_Common::log($level, $msg); - } -}PEAR-1.9.0/PEAR/ChannelFile.php100664 764 764 143353 100664 10767 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ChannelFile.php 286951 2009-08-09 14:41:22Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Needed for error handling - */ -require_once 'PEAR/ErrorStack.php'; -require_once 'PEAR/XMLParser.php'; -require_once 'PEAR/Common.php'; - -/** - * Error code if the channel.xml tag does not contain a valid version - */ -define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); -/** - * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, - * currently - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); - -/**#@+ - * Validation errors - */ -/** - * Error code when channel name is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); -/** - * Error code when channel name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); -/** - * Error code when channel summary is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); -/** - * Error code when channel summary is multi-line - */ -define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); -/** - * Error code when channel server is missing for protocol - */ -define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); -/** - * Error code when channel server is invalid for protocol - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); -/** - * Error code when a mirror name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); -/** - * Error code when a mirror type is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); -/** - * Error code when an attempt is made to generate xml, but the parsed content is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID', 23); -/** - * Error code when an empty package name validate regex is passed in - */ -define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); -/** - * Error code when a tag has no version - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); -/** - * Error code when a tag has no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); -/** - * Error code when a mirror does not exist but is called for in one of the set* - * methods. - */ -define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); -/** - * Error code when a server port is not numeric - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); -/** - * Error code when contains no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); -/** - * Error code when contains no type attribute in a protocol definition - */ -define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); -/** - * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel - */ -define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); -/** - * Error code when ssl attribute is present and is not "yes" - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); -/**#@-*/ - -/** - * Mirror types allowed. Currently only internet servers are recognized. - */ -$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); - - -/** - * The Channel handling class - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_ChannelFile -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * Supported channel.xml versions, for parsing - * @var array - * @access private - */ - var $_supportedVersions = array('1.0'); - - /** - * Parsed channel information - * @var array - * @access private - */ - var $_channelInfo; - - /** - * index into the subchannels array, used for parsing xml - * @var int - * @access private - */ - var $_subchannelIndex; - - /** - * index into the mirrors array, used for parsing xml - * @var int - * @access private - */ - var $_mirrorIndex; - - /** - * Flag used to determine the validity of parsed content - * @var boolean - * @access private - */ - var $_isValid = false; - - function PEAR_ChannelFile() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = false; - } - - /** - * @return array - * @access protected - */ - function _getErrorMessage() - { - return - array( - PEAR_CHANNELFILE_ERROR_INVALID_VERSION => - 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', - PEAR_CHANNELFILE_ERROR_NO_VERSION => - 'No version number found in tag', - PEAR_CHANNELFILE_ERROR_NO_XML_EXT => - '%error%', - PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => - 'Unable to create XML parser', - PEAR_CHANNELFILE_ERROR_PARSER_ERROR => - '%error%', - PEAR_CHANNELFILE_ERROR_NO_NAME => - 'Missing channel name', - PEAR_CHANNELFILE_ERROR_INVALID_NAME => - 'Invalid channel %tag% "%name%"', - PEAR_CHANNELFILE_ERROR_NO_SUMMARY => - 'Missing channel summary', - PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => - 'Channel summary should be on one line, but is multi-line', - PEAR_CHANNELFILE_ERROR_NO_HOST => - 'Missing channel server for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_HOST => - 'Server name "%server%" is invalid for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => - 'Invalid mirror name "%name%", mirror type %type%', - PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => - 'Invalid mirror type "%type%"', - PEAR_CHANNELFILE_ERROR_INVALID => - 'Cannot generate xml, contents are invalid', - PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => - 'packagenameregex cannot be empty', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => - '%parent% %protocol% function has no version', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => - '%parent% %protocol% function has no name', - PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => - '%parent% rest baseurl has no type', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => - 'Validation package has no name in tag', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => - 'Validation package "%package%" has no version', - PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => - 'Mirror "%mirror%" does not exist', - PEAR_CHANNELFILE_ERROR_INVALID_PORT => - 'Port "%port%" must be numeric', - PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => - ' tag must contain version attribute', - PEAR_CHANNELFILE_URI_CANT_MIRROR => - 'The __uri pseudo-channel cannot have mirrors', - PEAR_CHANNELFILE_ERROR_INVALID_SSL => - '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', - ); - } - - /** - * @param string contents of package.xml file - * @return bool success of parsing - */ - function fromXmlString($data) - { - if (preg_match('/_supportedVersions)) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', - array('version' => $channelversion[1])); - return false; - } - $parser = new PEAR_XMLParser; - $result = $parser->parse($data); - if ($result !== true) { - if ($result->getCode() == 1) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', - array('error' => $result->getMessage())); - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); - } - return false; - } - $this->_channelInfo = $parser->getData(); - return true; - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); - return false; - } - } - - /** - * @return array - */ - function toArray() - { - if (!$this->_isValid && !$this->validate()) { - return false; - } - return $this->_channelInfo; - } - - /** - * @param array - * @static - * @return PEAR_ChannelFile|false false if invalid - */ - function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') - { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - if (!$a->validate()) { - $a = false; - return $a; - } - return $a; - } - - /** - * Unlike {@link fromArray()} this does not do any validation - * @param array - * @static - * @return PEAR_ChannelFile - */ - function &fromArrayWithErrors($data, $compatibility = false, - $stackClass = 'PEAR_ErrorStack') - { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - return $a; - } - - /** - * @param array - * @access private - */ - function _fromArray($data) - { - $this->_channelInfo = $data; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getErrors($purge = false) - { - return $this->_stack->getErrors($purge); - } - - /** - * Unindent given string (?) - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } - } - return $data; - } - - /** - * Parse a channel.xml file. Expects the name of - * a channel xml file as input. - * - * @param string $descfile name of channel xml file - * @return bool success of parsing - */ - function fromXmlFile($descfile) - { - if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || - (!$fp = fopen($descfile, 'r'))) { - require_once 'PEAR.php'; - return PEAR::raiseError("Unable to open $descfile"); - } - - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - return $this->fromXmlString($data); - } - - /** - * Parse channel information from different sources - * - * This method is able to extract information about a channel - * from an .xml file or a string - * - * @access public - * @param string Filename of the source or the source itself - * @return bool - */ - function fromAny($info) - { - if (is_string($info) && file_exists($info) && strlen($info) < 255) { - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = $this->fromXmlFile($info); - } else { - $fp = fopen($info, "r"); - $test = fread($fp, 5); - fclose($fp); - if ($test == "fromXmlFile($info); - } - } - if (PEAR::isError($info)) { - require_once 'PEAR.php'; - return PEAR::raiseError($info); - } - } - if (is_string($info)) { - $info = $this->fromXmlString($info); - } - return $info; - } - - /** - * Return an XML document based on previous parsing and modifications - * - * @return string XML data - * - * @access public - */ - function toXml() - { - if (!$this->_isValid && !$this->validate()) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); - return false; - } - if (!isset($this->_channelInfo['attribs']['version'])) { - $this->_channelInfo['attribs']['version'] = '1.0'; - } - $channelInfo = $this->_channelInfo; - $ret = "\n"; - $ret .= " - $channelInfo[name] - " . htmlspecialchars($channelInfo['summary'])." -"; - if (isset($channelInfo['suggestedalias'])) { - $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; - } - if (isset($channelInfo['validatepackage'])) { - $ret .= ' ' . - htmlspecialchars($channelInfo['validatepackage']['_content']) . - "\n"; - } - $ret .= " \n"; - $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); - } - $ret .= " \n"; - if (isset($channelInfo['servers']['mirror'])) { - $ret .= $this->_makeMirrorsXml($channelInfo); - } - $ret .= " \n"; - $ret .= ""; - return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); - } - - /** - * Generate the tag - * @access private - */ - function _makeRestXml($info, $indent) - { - $ret = $indent . "\n"; - if (isset($info['baseurl']) && !isset($info['baseurl'][0])) { - $info['baseurl'] = array($info['baseurl']); - } - - if (isset($info['baseurl'])) { - foreach ($info['baseurl'] as $url) { - $ret .= "$indent \n"; - } - } - $ret .= $indent . "\n"; - return $ret; - } - - /** - * Generate the tag - * @access private - */ - function _makeMirrorsXml($channelInfo) - { - $ret = ""; - if (!isset($channelInfo['servers']['mirror'][0])) { - $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); - } - foreach ($channelInfo['servers']['mirror'] as $mirror) { - $ret .= ' _makeRestXml($mirror['rest'], ' '); - } - $ret .= " \n"; - } else { - $ret .= "/>\n"; - } - } - return $ret; - } - - /** - * Generate the tag - * @access private - */ - function _makeFunctionsXml($functions, $indent, $rest = false) - { - $ret = ''; - if (!isset($functions[0])) { - $functions = array($functions); - } - foreach ($functions as $function) { - $ret .= "$indent\n"; - } - return $ret; - } - - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params); - $this->_isValid = false; - } - - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params); - } - - /** - * Validate parsed file. - * - * @access public - * @return boolean - */ - function validate() - { - $this->_isValid = true; - $info = $this->_channelInfo; - if (empty($info['name'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); - } elseif (!$this->validChannelServer($info['name'])) { - if ($info['name'] != '__uri') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', - 'name' => $info['name'])); - } - } - if (empty($info['summary'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (isset($info['suggestedalias'])) { - if (!$this->validChannelServer($info['suggestedalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); - } - } - if (isset($info['localalias'])) { - if (!$this->validChannelServer($info['localalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'localalias', 'name' =>$info['localalias'])); - } - } - if (isset($info['validatepackage'])) { - if (!isset($info['validatepackage']['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); - } - if (!isset($info['validatepackage']['attribs']['version'])) { - $content = isset($info['validatepackage']['_content']) ? - $info['validatepackage']['_content'] : - null; - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, - array('package' => $content)); - } - } - - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && - !is_numeric($info['servers']['primary']['attribs']['port'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, - array('port' => $info['servers']['primary']['attribs']['port'])); - } - - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && - $info['servers']['primary']['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['servers']['primary']['attribs']['ssl'], - 'server' => $info['name'])); - } - - if (isset($info['servers']['primary']['rest']) && - isset($info['servers']['primary']['rest']['baseurl'])) { - $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); - } - if (isset($info['servers']['mirror'])) { - if ($this->_channelInfo['name'] == '__uri') { - $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); - } - if (!isset($info['servers']['mirror'][0])) { - $info['servers']['mirror'] = array($info['servers']['mirror']); - } - foreach ($info['servers']['mirror'] as $mirror) { - if (!isset($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, - array('type' => 'mirror')); - } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, - array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); - } - if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); - } - if (isset($mirror['rest'])) { - $this->_validateFunctions('rest', $mirror['rest']['baseurl'], - $mirror['attribs']['host']); - } - } - } - return $this->_isValid; - } - - /** - * @param string rest - protocol name this function applies to - * @param array the functions - * @param string the name of the parent element (mirror name, for instance) - */ - function _validateFunctions($protocol, $functions, $parent = '') - { - if (!isset($functions[0])) { - $functions = array($functions); - } - - foreach ($functions as $function) { - if (!isset($function['_content']) || empty($function['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, - array('parent' => $parent, 'protocol' => $protocol)); - } - - if ($protocol == 'rest') { - if (!isset($function['attribs']['type']) || - empty($function['attribs']['type'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE, - array('parent' => $parent, 'protocol' => $protocol)); - } - } else { - if (!isset($function['attribs']['version']) || - empty($function['attribs']['version'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, - array('parent' => $parent, 'protocol' => $protocol)); - } - } - } - } - - /** - * Test whether a string contains a valid channel server. - * @param string $ver the package version to test - * @return bool - */ - function validChannelServer($server) - { - if ($server == '__uri') { - return true; - } - return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); - } - - /** - * @return string|false - */ - function getName() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; - } - - return false; - } - - /** - * @return string|false - */ - function getServer() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; - } - - return false; - } - - /** - * @return int|80 port number to connect to - */ - function getPort($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['port'])) { - return $mir['attribs']['port']; - } - - if ($this->getSSL($mirror)) { - return 443; - } - - return 80; - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { - return $this->_channelInfo['servers']['primary']['attribs']['port']; - } - - if ($this->getSSL()) { - return 443; - } - - return 80; - } - - /** - * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel - */ - function getSSL($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['ssl'])) { - return true; - } - - return false; - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - return true; - } - - return false; - } - - /** - * @return string|false - */ - function getSummary() - { - if (isset($this->_channelInfo['summary'])) { - return $this->_channelInfo['summary']; - } - - return false; - } - - /** - * @param string protocol type - * @param string Mirror name - * @return array|false - */ - function getFunctions($protocol, $mirror = false) - { - if ($this->getName() == '__uri') { - return false; - } - - $function = $protocol == 'rest' ? 'baseurl' : 'function'; - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir[$protocol][$function])) { - return $mir[$protocol][$function]; - } - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { - return $this->_channelInfo['servers']['primary'][$protocol][$function]; - } - - return false; - } - - /** - * @param string Protocol type - * @param string Function name (null to return the - * first protocol of the type requested) - * @param string Mirror name, if any - * @return array - */ - function getFunction($type, $name = null, $mirror = false) - { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } - - foreach ($protocols as $protocol) { - if ($name === null) { - return $protocol; - } - - if ($protocol['_content'] != $name) { - continue; - } - - return $protocol; - } - - return false; - } - - /** - * @param string protocol type - * @param string protocol name - * @param string version - * @param string mirror name - * @return boolean - */ - function supports($type, $name = null, $mirror = false, $version = '1.0') - { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } - - foreach ($protocols as $protocol) { - if ($protocol['attribs']['version'] != $version) { - continue; - } - - if ($name === null) { - return true; - } - - if ($protocol['_content'] != $name) { - continue; - } - - return true; - } - - return false; - } - - /** - * Determines whether a channel supports Representational State Transfer (REST) protocols - * for retrieving channel information - * @param string - * @return bool - */ - function supportsREST($mirror = false) - { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; - } - - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - return isset($mir['rest']); - } - - return false; - } - - return isset($this->_channelInfo['servers']['primary']['rest']); - } - - /** - * Get the URL to access a base resource. - * - * Hyperlinks in the returned xml will be used to retrieve the proper information - * needed. This allows extreme extensibility and flexibility in implementation - * @param string Resource Type to retrieve - */ - function getBaseURL($resourceType, $mirror = false) - { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; - } - - if ($mirror) { - $mir = $this->getMirror($mirror); - if (!$mir) { - return false; - } - - $rest = $mir['rest']; - } else { - $rest = $this->_channelInfo['servers']['primary']['rest']; - } - - if (!isset($rest['baseurl'][0])) { - $rest['baseurl'] = array($rest['baseurl']); - } - - foreach ($rest['baseurl'] as $baseurl) { - if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { - return $baseurl['_content']; - } - } - - return false; - } - - /** - * Since REST does not implement RPC, provide this as a logical wrapper around - * resetFunctions for REST - * @param string|false mirror name, if any - */ - function resetREST($mirror = false) - { - return $this->resetFunctions('rest', $mirror); - } - - /** - * Empty all protocol definitions - * @param string protocol type - * @param string|false mirror name, if any - */ - function resetFunctions($type, $mirror = false) - { - if ($mirror) { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); - } - - foreach ($mirrors as $i => $mir) { - if ($mir['attribs']['host'] == $mirror) { - if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { - unset($this->_channelInfo['servers']['mirror'][$i][$type]); - } - - return true; - } - } - - return false; - } - - return false; - } - - if (isset($this->_channelInfo['servers']['primary'][$type])) { - unset($this->_channelInfo['servers']['primary'][$type]); - } - - return true; - } - - /** - * Set a channel's protocols to the protocols supported by pearweb - */ - function setDefaultPEARProtocols($version = '1.0', $mirror = false) - { - switch ($version) { - case '1.0' : - $this->resetREST($mirror); - - if (!isset($this->_channelInfo['servers'])) { - $this->_channelInfo['servers'] = array('primary' => - array('rest' => array())); - } elseif (!isset($this->_channelInfo['servers']['primary'])) { - $this->_channelInfo['servers']['primary'] = array('rest' => array()); - } - - return true; - break; - default : - return false; - break; - } - } - - /** - * @return array - */ - function getMirrors() - { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); - } - - return $mirrors; - } - - return array(); - } - - /** - * Get the unserialized XML representing a mirror - * @return array|false - */ - function getMirror($server) - { - foreach ($this->getMirrors() as $mirror) { - if ($mirror['attribs']['host'] == $server) { - return $mirror; - } - } - - return false; - } - - /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_NAME - * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME - */ - function setName($name) - { - return $this->setServer($name); - } - - /** - * Set the socket number (port) that is used to connect to this channel - * @param integer - * @param string|false name of the mirror server, or false for the primary - */ - function setPort($port, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; - return true; - } - } - - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; - $this->_isValid = false; - return true; - } - } - - $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; - $this->_isValid = false; - return true; - } - - /** - * Set the socket number (port) that is used to connect to this channel - * @param bool Determines whether to turn on SSL support or turn it off - * @param string|false name of the mirror server, or false for the primary - */ - function setSSL($ssl = true, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror'][$i] - ['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); - } - } else { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; - } - - return true; - } - } - - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); - } - } else { - $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; - } - - $this->_isValid = false; - return true; - } - } - - if ($ssl) { - $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; - } else { - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); - } - } - - $this->_isValid = false; - return true; - } - - /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_SERVER - * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER - */ - function setServer($server, $mirror = false) - { - if (empty($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); - return false; - } elseif (!$this->validChannelServer($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'name', 'name' => $server)); - return false; - } - - if ($mirror) { - $found = false; - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $found = true; - break; - } - } - - if (!$found) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; - return true; - } - - $this->_channelInfo['name'] = $server; - return true; - } - - /** - * @param string - * @return boolean success - * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY - * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY - */ - function setSummary($summary) - { - if (empty($summary)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - return false; - } elseif (strpos(trim($summary), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $summary)); - } - - $this->_channelInfo['summary'] = $summary; - return true; - } - - /** - * @param string - * @param boolean determines whether the alias is in channel.xml or local - * @return boolean success - */ - function setAlias($alias, $local = false) - { - if (!$this->validChannelServer($alias)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' => $alias)); - return false; - } - - if ($local) { - $this->_channelInfo['localalias'] = $alias; - } else { - $this->_channelInfo['suggestedalias'] = $alias; - } - - return true; - } - - /** - * @return string - */ - function getAlias() - { - if (isset($this->_channelInfo['localalias'])) { - return $this->_channelInfo['localalias']; - } - if (isset($this->_channelInfo['suggestedalias'])) { - return $this->_channelInfo['suggestedalias']; - } - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; - } - return ''; - } - - /** - * Set the package validation object if it differs from PEAR's default - * The class must be includeable via changing _ in the classname to path separator, - * but no checking of this is made. - * @param string|false pass in false to reset to the default packagename regex - * @return boolean success - */ - function setValidationPackage($validateclass, $version) - { - if (empty($validateclass)) { - unset($this->_channelInfo['validatepackage']); - } - $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); - $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); - } - - /** - * Add a protocol to the provides section - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - * @param string mirror name, if this is a mirror's protocol - * @return bool - */ - function addFunction($type, $version, $name = '', $mirror = false) - { - if ($mirror) { - return $this->addMirrorFunction($mirror, $type, $version, $name); - } - - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { - if (!isset($this->_channelInfo['servers'])) { - $this->_channelInfo['servers'] = array('primary' => - array($type => array())); - } elseif (!isset($this->_channelInfo['servers']['primary'])) { - $this->_channelInfo['servers']['primary'] = array($type => array()); - } - - $this->_channelInfo['servers']['primary'][$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { - $this->_channelInfo['servers']['primary'][$type]['function'] = array( - $this->_channelInfo['servers']['primary'][$type]['function']); - } - - $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; - return true; - } - /** - * Add a protocol to a mirror's provides section - * @param string mirror name (server) - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - */ - function addMirrorFunction($mirror, $type, $version, $name = '') - { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; - } - } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; - } - } - - if (!$setmirror) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($setmirror[$type]['function'])) { - $setmirror[$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror[$type]['function'][0])) { - $setmirror[$type]['function'] = array($setmirror[$type]['function']); - } - - $setmirror[$type]['function'][] = $set; - $this->_isValid = false; - return true; - } - - /** - * @param string Resource Type this url links to - * @param string URL - * @param string|false mirror name, if this is not a primary server REST base URL - */ - function setBaseURL($resourceType, $url, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; - } - } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; - } - } - } else { - $setmirror = &$this->_channelInfo['servers']['primary']; - } - - $set = array('attribs' => array('type' => $resourceType), '_content' => $url); - if (!isset($setmirror['rest'])) { - $setmirror['rest'] = array(); - } - - if (!isset($setmirror['rest']['baseurl'])) { - $setmirror['rest']['baseurl'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror['rest']['baseurl'][0])) { - $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); - } - - foreach ($setmirror['rest']['baseurl'] as $i => $url) { - if ($url['attribs']['type'] == $resourceType) { - $this->_isValid = false; - $setmirror['rest']['baseurl'][$i] = $set; - return true; - } - } - - $setmirror['rest']['baseurl'][] = $set; - $this->_isValid = false; - return true; - } - - /** - * @param string mirror server - * @param int mirror http port - * @return boolean - */ - function addMirror($server, $port = null) - { - if ($this->_channelInfo['name'] == '__uri') { - return false; // the __uri channel cannot have mirrors by definition - } - - $set = array('attribs' => array('host' => $server)); - if (is_numeric($port)) { - $set['attribs']['port'] = $port; - } - - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_channelInfo['servers']['mirror'] = $set; - return true; - } - - if (!isset($this->_channelInfo['servers']['mirror'][0])) { - $this->_channelInfo['servers']['mirror'] = - array($this->_channelInfo['servers']['mirror']); - } - - $this->_channelInfo['servers']['mirror'][] = $set; - return true; - } - - /** - * Retrieve the name of the validation package for this channel - * @return string|false - */ - function getValidationPackage() - { - if (!$this->_isValid && !$this->validate()) { - return false; - } - - if (!isset($this->_channelInfo['validatepackage'])) { - return array('attribs' => array('version' => 'default'), - '_content' => 'PEAR_Validate'); - } - - return $this->_channelInfo['validatepackage']; - } - - /** - * Retrieve the object that can be used for custom validation - * @param string|false the name of the package to validate. If the package is - * the channel validation package, PEAR_Validate is returned - * @return PEAR_Validate|false false is returned if the validation package - * cannot be located - */ - function &getValidationObject($package = false) - { - if (!class_exists('PEAR_Validate')) { - require_once 'PEAR/Validate.php'; - } - - if (!$this->_isValid) { - if (!$this->validate()) { - $a = false; - return $a; - } - } - - if (isset($this->_channelInfo['validatepackage'])) { - if ($package == $this->_channelInfo['validatepackage']) { - // channel validation packages are always validated by PEAR_Validate - $val = &new PEAR_Validate; - return $val; - } - - if (!class_exists(str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']))) { - if ($this->isIncludeable(str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php')) { - include_once str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php'; - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; - } else { - $a = false; - return $a; - } - } else { - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; - } - } else { - $val = &new PEAR_Validate; - } - - return $val; - } - - function isIncludeable($path) - { - $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($possibilities as $dir) { - if (file_exists($dir . DIRECTORY_SEPARATOR . $path) - && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { - return true; - } - } - - return false; - } - - /** - * This function is used by the channel updater and retrieves a value set by - * the registry, or the current time if it has not been set - * @return string - */ - function lastModified() - { - if (isset($this->_channelInfo['_lastmodified'])) { - return $this->_channelInfo['_lastmodified']; - } - - return time(); - } -}PEAR-1.9.0/PEAR/Command.php100664 764 764 30633 100664 10151 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Command.php 286494 2009-07-29 06:57:11Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Needed for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Frontend.php'; -require_once 'PEAR/XMLParser.php'; - -/** - * List of commands and what classes they are implemented in. - * @var array command => implementing class - */ -$GLOBALS['_PEAR_Command_commandlist'] = array(); - -/** - * List of commands and their descriptions - * @var array command => description - */ -$GLOBALS['_PEAR_Command_commanddesc'] = array(); - -/** - * List of shortcuts to common commands. - * @var array shortcut => command - */ -$GLOBALS['_PEAR_Command_shortcuts'] = array(); - -/** - * Array of command objects - * @var array class => object - */ -$GLOBALS['_PEAR_Command_objects'] = array(); - -/** - * PEAR command class, a simple factory class for administrative - * commands. - * - * How to implement command classes: - * - * - The class must be called PEAR_Command_Nnn, installed in the - * "PEAR/Common" subdir, with a method called getCommands() that - * returns an array of the commands implemented by the class (see - * PEAR/Command/Install.php for an example). - * - * - The class must implement a run() function that is called with three - * params: - * - * (string) command name - * (array) assoc array with options, freely defined by each - * command, for example: - * array('force' => true) - * (array) list of the other parameters - * - * The run() function returns a PEAR_CommandResponse object. Use - * these methods to get information: - * - * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) - * *_PARTIAL means that you need to issue at least - * one more command to complete the operation - * (used for example for validation steps). - * - * string getMessage() Returns a message for the user. Remember, - * no HTML or other interface-specific markup. - * - * If something unexpected happens, run() returns a PEAR error. - * - * - DON'T OUTPUT ANYTHING! Return text for output instead. - * - * - DON'T USE HTML! The text you return will be used from both Gtk, - * web and command-line interfaces, so for now, keep everything to - * plain text. - * - * - DON'T USE EXIT OR DIE! Always use pear errors. From static - * classes do PEAR::raiseError(), from other classes do - * $this->raiseError(). - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command -{ - // {{{ factory() - - /** - * Get the right object for executing a command. - * - * @param string $command The name of the command - * @param object $config Instance of PEAR_Config object - * - * @return object the command object or a PEAR error - * - * @access public - * @static - */ - function &factory($command, &$config) - { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; - } - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; - } - if (!class_exists($class)) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; - } - $ui =& PEAR_Command::getFrontendObject(); - $obj = &new $class($ui, $config); - return $obj; - } - - // }}} - // {{{ & getObject() - function &getObject($command) - { - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; - } - if (!class_exists($class)) { - return PEAR::raiseError("unknown command `$command'"); - } - $ui =& PEAR_Command::getFrontendObject(); - $config = &PEAR_Config::singleton(); - $obj = &new $class($ui, $config); - return $obj; - } - - // }}} - // {{{ & getFrontendObject() - - /** - * Get instance of frontend object. - * - * @return object|PEAR_Error - * @static - */ - function &getFrontendObject() - { - $a = &PEAR_Frontend::singleton(); - return $a; - } - - // }}} - // {{{ & setFrontendClass() - - /** - * Load current frontend class. - * - * @param string $uiclass Name of class implementing the frontend - * - * @return object the frontend object, or a PEAR error - * @static - */ - function &setFrontendClass($uiclass) - { - $a = &PEAR_Frontend::setFrontendClass($uiclass); - return $a; - } - - // }}} - // {{{ setFrontendType() - - /** - * Set current frontend. - * - * @param string $uitype Name of the frontend type (for example "CLI") - * - * @return object the frontend object, or a PEAR error - * @static - */ - function setFrontendType($uitype) - { - $uiclass = 'PEAR_Frontend_' . $uitype; - return PEAR_Command::setFrontendClass($uiclass); - } - - // }}} - // {{{ registerCommands() - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * - * @param bool (optional) if FALSE (default), the new list of - * commands should replace the current one. If TRUE, - * new entries will be merged with old. - * - * @param string (optional) where (what directory) to look for - * classes, defaults to the Command subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * - * @access public - * @static - */ - function registerCommands($merge = false, $dir = null) - { - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Command'; - } - if (!is_dir($dir)) { - return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); - } - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerCommands: opendir($dir) failed"); - } - if (!$merge) { - $GLOBALS['_PEAR_Command_commandlist'] = array(); - } - - while ($file = readdir($dp)) { - if ($file{0} == '.' || substr($file, -4) != '.xml') { - continue; - } - - $f = substr($file, 0, -4); - $class = "PEAR_Command_" . $f; - // List of commands - if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { - $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php'; - } - - $parser->parse(file_get_contents("$dir/$file")); - $implements = $parser->getData(); - foreach ($implements as $command => $desc) { - if ($command == 'attribs') { - continue; - } - - if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return PEAR::raiseError('Command "' . $command . '" already registered in ' . - 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - - $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; - $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; - if (isset($desc['shortcut'])) { - $shortcut = $desc['shortcut']; - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { - return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . - 'registered to command "' . $command . '" in class "' . - $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; - } - - if (isset($desc['options']) && $desc['options']) { - foreach ($desc['options'] as $oname => $option) { - if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { - return PEAR::raiseError('Option "' . $oname . '" short option "' . - $option['shortopt'] . '" must be ' . - 'only 1 character in Command "' . $command . '" in class "' . - $class . '"'); - } - } - } - } - } - - ksort($GLOBALS['_PEAR_Command_shortcuts']); - ksort($GLOBALS['_PEAR_Command_commandlist']); - @closedir($dp); - return true; - } - - // }}} - // {{{ getCommands() - - /** - * Get the list of currently supported commands, and what - * classes implement them. - * - * @return array command => implementing class - * - * @access public - * @static - */ - function getCommands() - { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - return $GLOBALS['_PEAR_Command_commandlist']; - } - - // }}} - // {{{ getShortcuts() - - /** - * Get the list of command shortcuts. - * - * @return array shortcut => command - * - * @access public - * @static - */ - function getShortcuts() - { - if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { - PEAR_Command::registerCommands(); - } - return $GLOBALS['_PEAR_Command_shortcuts']; - } - - // }}} - // {{{ getGetoptArgs() - - /** - * Compiles arguments for getopt. - * - * @param string $command command to get optstring for - * @param string $short_args (reference) short getopt format - * @param array $long_args (reference) long getopt format - * - * @return void - * - * @access public - * @static - */ - function getGetoptArgs($command, &$short_args, &$long_args) - { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return null; - } - $obj = &PEAR_Command::getObject($command); - return $obj->getGetoptArgs($command, $short_args, $long_args); - } - - // }}} - // {{{ getDescription() - - /** - * Get description for a command. - * - * @param string $command Name of the command - * - * @return string command description - * - * @access public - * @static - */ - function getDescription($command) - { - if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { - return null; - } - return $GLOBALS['_PEAR_Command_commanddesc'][$command]; - } - - // }}} - // {{{ getHelp() - - /** - * Get help for command. - * - * @param string $command Name of the command to return help for - * - * @access public - * @static - */ - function getHelp($command) - { - $cmds = PEAR_Command::getCommands(); - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (isset($cmds[$command])) { - $obj = &PEAR_Command::getObject($command); - return $obj->getHelp($command); - } - return false; - } - // }}} -}PEAR-1.9.0/PEAR/Common.php100664 764 764 62255 100664 10030 - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 282969 2009-06-28 23:09:27Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1.0 - * @deprecated File deprecated since Release 1.4.0a1 - */ - -/** - * Include error handling - */ -require_once 'PEAR.php'; - -/** - * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() - */ -define('PEAR_COMMON_ERROR_INVALIDPHP', 1); -define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); -define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); - -// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 -define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); -define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); - -// XXX far from perfect :-) -define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . - ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . - '\\z/'); - -define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); -define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); - -// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED -define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); -define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); - -define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); -define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); - -define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); - -/** - * List of temporary files and directories registered by - * PEAR_Common::addTempFile(). - * @var array - */ -$GLOBALS['_PEAR_Common_tempfiles'] = array(); - -/** - * Valid maintainer roles - * @var array - */ -$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); - -/** - * Valid release states - * @var array - */ -$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); - -/** - * Valid dependency types - * @var array - */ -$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); - -/** - * Valid dependency relations - * @var array - */ -$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); - -/** - * Valid file roles - * @var array - */ -$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); - -/** - * Valid replacement types - * @var array - */ -$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); - -/** - * Valid "provide" types - * @var array - */ -$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); - -/** - * Valid "provide" types - * @var array - */ -$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); - -/** - * Class providing common functionality for PEAR administration classes. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - * @deprecated This class will disappear, and its components will be spread - * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 - */ -class PEAR_Common extends PEAR -{ - /** - * User Interface object (PEAR_Frontend_* class). If null, - * the log() method uses print. - * @var object - */ - var $ui = null; - - /** - * Configuration object (PEAR_Config). - * @var PEAR_Config - */ - var $config = null; - - /** stack of elements, gives some sort of XML context */ - var $element_stack = array(); - - /** name of currently parsed XML element */ - var $current_element; - - /** array of attributes of the currently parsed XML element */ - var $current_attributes = array(); - - /** assoc with information about a package */ - var $pkginfo = array(); - - var $current_path = null; - - /** - * Flag variable used to mark a valid package file - * @var boolean - * @access private - */ - var $_validPackageFile; - - /** - * PEAR_Common constructor - * - * @access public - */ - function PEAR_Common() - { - parent::PEAR(); - $this->config = &PEAR_Config::singleton(); - $this->debug = $this->config->get('verbose'); - } - - /** - * PEAR_Common destructor - * - * @access private - */ - function _PEAR_Common() - { - // doesn't work due to bug #14744 - //$tempfiles = $this->_tempfiles; - $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; - while ($file = array_shift($tempfiles)) { - if (@is_dir($file)) { - if (!class_exists('System')) { - require_once 'System.php'; - } - - System::rm(array('-rf', $file)); - } elseif (file_exists($file)) { - unlink($file); - } - } - } - - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * - * @return void - * - * @access public - */ - function addTempFile($file) - { - if (!class_exists('PEAR_Frontend')) { - require_once 'PEAR/Frontend.php'; - } - PEAR_Frontend::addTempFile($file); - } - - /** - * Wrapper to System::mkDir(), creates a directory as well as - * any necessary parent directories. - * - * @param string $dir directory name - * - * @return bool TRUE on success, or a PEAR error - * - * @access public - */ - function mkDirHier($dir) - { - // Only used in Installer - move it there ? - $this->log(2, "+ create dir $dir"); - if (!class_exists('System')) { - require_once 'System.php'; - } - return System::mkDir(array('-p', $dir)); - } - - /** - * Logging method. - * - * @param int $level log level (0 is quiet, higher is noisier) - * @param string $msg message to write to the log - * - * @return void - * - * @access public - * @static - */ - function log($level, $msg, $append_crlf = true) - { - if ($this->debug >= $level) { - if (!class_exists('PEAR_Frontend')) { - require_once 'PEAR/Frontend.php'; - } - - $ui = &PEAR_Frontend::singleton(); - if (is_a($ui, 'PEAR_Frontend')) { - $ui->log($msg, $append_crlf); - } else { - print "$msg\n"; - } - } - } - - /** - * Create and register a temporary directory. - * - * @param string $tmpdir (optional) Directory to use as tmpdir. - * Will use system defaults (for example - * /tmp or c:\windows\temp) if not specified - * - * @return string name of created directory - * - * @access public - */ - function mkTempDir($tmpdir = '') - { - $topt = $tmpdir ? array('-t', $tmpdir) : array(); - $topt = array_merge($topt, array('-d', 'pear')); - if (!class_exists('System')) { - require_once 'System.php'; - } - - if (!$tmpdir = System::mktemp($topt)) { - return false; - } - - $this->addTempFile($tmpdir); - return $tmpdir; - } - - /** - * Set object that represents the frontend to be used. - * - * @param object Reference of the frontend object - * @return void - * @access public - */ - function setFrontendObject(&$ui) - { - $this->ui = &$ui; - } - - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - if ($include) { - $i--; - } - return array_slice($states, $i + 1); - } - - /** - * Get the valid roles for a PEAR package maintainer - * - * @return array - * @static - */ - function getUserRoles() - { - return $GLOBALS['_PEAR_Common_maintainer_roles']; - } - - /** - * Get the valid package release states of packages - * - * @return array - * @static - */ - function getReleaseStates() - { - return $GLOBALS['_PEAR_Common_release_states']; - } - - /** - * Get the implemented dependency types (php, ext, pkg etc.) - * - * @return array - * @static - */ - function getDependencyTypes() - { - return $GLOBALS['_PEAR_Common_dependency_types']; - } - - /** - * Get the implemented dependency relations (has, lt, ge etc.) - * - * @return array - * @static - */ - function getDependencyRelations() - { - return $GLOBALS['_PEAR_Common_dependency_relations']; - } - - /** - * Get the implemented file roles - * - * @return array - * @static - */ - function getFileRoles() - { - return $GLOBALS['_PEAR_Common_file_roles']; - } - - /** - * Get the implemented file replacement types in - * - * @return array - * @static - */ - function getReplacementTypes() - { - return $GLOBALS['_PEAR_Common_replacement_types']; - } - - /** - * Get the implemented file replacement types in - * - * @return array - * @static - */ - function getProvideTypes() - { - return $GLOBALS['_PEAR_Common_provide_types']; - } - - /** - * Get the implemented file replacement types in - * - * @return array - * @static - */ - function getScriptPhases() - { - return $GLOBALS['_PEAR_Common_script_phases']; - } - - /** - * Test whether a string contains a valid package name. - * - * @param string $name the package name to test - * - * @return bool - * - * @access public - */ - function validPackageName($name) - { - return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); - } - - /** - * Test whether a string contains a valid package version. - * - * @param string $ver the package version to test - * - * @return bool - * - * @access public - */ - function validPackageVersion($ver) - { - return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); - } - - /** - * @param string $path relative or absolute include path - * @return boolean - * @static - */ - function isIncludeable($path) - { - if (file_exists($path) && is_readable($path)) { - return true; - } - - $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($ipath as $include) { - $test = realpath($include . DIRECTORY_SEPARATOR . $path); - if (file_exists($test) && is_readable($test)) { - return true; - } - } - - return false; - } - - function _postProcessChecks($pf) - { - if (!PEAR::isError($pf)) { - return $this->_postProcessValidPackagexml($pf); - } - - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; - } - - /** - * Returns information about a package file. Expects the name of - * a gzipped tar file as input. - * - * @param string $file name of .tgz file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromTgzFile() instead - * - */ - function infoFromTgzFile($file) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); - return $this->_postProcessChecks($pf); - } - - /** - * Returns information about a package file. Expects the name of - * a package xml file as input. - * - * @param string $descfile name of package xml file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromPackageFile() instead - * - */ - function infoFromDescriptionFile($descfile) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - return $this->_postProcessChecks($pf); - } - - /** - * Returns information about a package file. Expects the contents - * of a package xml file as input. - * - * @param string $data contents of package.xml file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromXmlstring() instead - * - */ - function infoFromString($data) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); - return $this->_postProcessChecks($pf); - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return array - */ - function _postProcessValidPackagexml(&$pf) - { - if (!is_a($pf, 'PEAR_PackageFile_v2')) { - $this->pkginfo = $pf->toArray(); - return $this->pkginfo; - } - - // sort of make this into a package.xml 1.0-style array - // changelog is not converted to old format. - $arr = $pf->toArray(true); - $arr = array_merge($arr, $arr['old']); - unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'], - $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'], - $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'], - $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'], - $arr['helper'], $arr['contributor']); - $arr['filelist'] = $pf->getFilelist(); - $this->pkginfo = $arr; - return $arr; - } - - /** - * Returns package information from different sources - * - * This method is able to extract information about a package - * from a .tgz archive or from a XML package definition file. - * - * @access public - * @param string Filename of the source ('package.xml', '.tgz') - * @return string - * @deprecated use PEAR_PackageFile->fromAnyFile() instead - */ - function infoFromAny($info) - { - if (is_string($info) && file_exists($info)) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; - } - - return $this->_postProcessValidPackagexml($pf); - } - - return $info; - } - - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @param array $pkginfo package info - * - * @return string XML data - * - * @access public - * @deprecated use a PEAR_PackageFile_v* object's generator instead - */ - function xmlFromInfo($pkginfo) - { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - $pf = &$packagefile->fromArray($pkginfo); - $gen = &$pf->getDefaultGenerator(); - return $gen->toXml(PEAR_VALIDATE_PACKAGING); - } - - /** - * Validate XML package definition file. - * - * @param string $info Filename of the package archive or of the - * package definition file - * @param array $errors Array that will contain the errors - * @param array $warnings Array that will contain the warnings - * @param string $dir_prefix (optional) directory where source files - * may be found, or empty if they are not available - * @access public - * @return boolean - * @deprecated use the validation of PEAR_PackageFile objects - */ - function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') - { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); - } else { - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); - } - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - if ($error['level'] == 'error') { - $errors[] = $error['message']; - } else { - $warnings[] = $error['message']; - } - } - } - - return false; - } - - return true; - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access public - * - */ - function buildProvidesArray($srcinfo) - { - $file = basename($srcinfo['source_file']); - $pn = ''; - if (isset($this->_packageName)) { - $pn = $this->_packageName; - } - - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->pkginfo['provides'][$key])) { - continue; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->pkginfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->pkginfo['provides'][$key])) { - continue; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { - continue; - } - - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access public - */ - function analyzeSourceCode($file) - { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'PEAR/PackageFile/v2/Validator.php'; - } - - $a = new PEAR_PackageFile_v2_Validator; - return $a->analyzeSourceCode($file); - } - - function detectDependencies($any, $status_callback = null) - { - if (!function_exists("token_get_all")) { - return false; - } - - if (PEAR::isError($info = $this->infoFromAny($any))) { - return $this->raiseError($info); - } - - if (!is_array($info)) { - return false; - } - - $deps = array(); - $used_c = $decl_c = $decl_f = $decl_m = array(); - foreach ($info['filelist'] as $file => $fa) { - $tmp = $this->analyzeSourceCode($file); - $used_c = @array_merge($used_c, $tmp['used_classes']); - $decl_c = @array_merge($decl_c, $tmp['declared_classes']); - $decl_f = @array_merge($decl_f, $tmp['declared_functions']); - $decl_m = @array_merge($decl_m, $tmp['declared_methods']); - $inheri = @array_merge($inheri, $tmp['inheritance']); - } - - $used_c = array_unique($used_c); - $decl_c = array_unique($decl_c); - $undecl_c = array_diff($used_c, $decl_c); - - return array('used_classes' => $used_c, - 'declared_classes' => $decl_c, - 'declared_methods' => $decl_m, - 'declared_functions' => $decl_f, - 'undeclared_classes' => $undecl_c, - 'inheritance' => $inheri, - ); - } - - /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir (optional) directory to save file in - * @param mixed $callback (optional) function/method to call for status - * updates - * - * @return string Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). - * - * @access public - * @deprecated in favor of PEAR_Downloader::downloadHttp() - */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) - { - if (!class_exists('PEAR_Downloader')) { - require_once 'PEAR/Downloader.php'; - } - return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); - } -} - -require_once 'PEAR/Config.php'; -require_once 'PEAR/PackageFile.php';PEAR-1.9.0/PEAR/Config.php100664 764 764 204452 100664 10022 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Config.php 286480 2009-07-29 02:50:02Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Required for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Registry.php'; -require_once 'PEAR/Installer/Role.php'; -require_once 'System.php'; - -/** - * Last created PEAR_Config instance. - * @var object - */ -$GLOBALS['_PEAR_Config_instance'] = null; -if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { - $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; -} else { - $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; -} - -// Below we define constants with default values for all configuration -// parameters except username/password. All of them can have their -// defaults set through environment variables. The reason we use the -// PHP_ prefix is for some security, PHP protects environment -// variables starting with PHP_*. - -// default channel and preferred mirror is based on whether we are invoked through -// the "pear" or the "pecl" command -if (!defined('PEAR_RUNTYPE')) { - define('PEAR_RUNTYPE', 'pear'); -} - -if (PEAR_RUNTYPE == 'pear') { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); -} else { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); -} - -if (getenv('PHP_PEAR_SYSCONF_DIR')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); -} elseif (getenv('SystemRoot')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); -} else { - define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); -} - -// Default for master_server -if (getenv('PHP_PEAR_MASTER_SERVER')) { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); -} else { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); -} - -// Default for http_proxy -if (getenv('PHP_PEAR_HTTP_PROXY')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); -} elseif (getenv('http_proxy')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); -} else { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); -} - -// Default for php_dir -if (getenv('PHP_PEAR_INSTALL_DIR')) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); -} else { - if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } -} - -// Default for ext_dir -if (getenv('PHP_PEAR_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); -} else { - if (ini_get('extension_dir')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); - } elseif (defined('PEAR_EXTENSION_DIR') && - file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); - } elseif (defined('PHP_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); - } -} - -// Default for doc_dir -if (getenv('PHP_PEAR_DOC_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); -} - -// Default for bin_dir -if (getenv('PHP_PEAR_BIN_DIR')) { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); -} - -// Default for data_dir -if (getenv('PHP_PEAR_DATA_DIR')) { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); -} - -// Default for cfg_dir -if (getenv('PHP_PEAR_CFG_DIR')) { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); -} - -// Default for www_dir -if (getenv('PHP_PEAR_WWW_DIR')) { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); -} - -// Default for test_dir -if (getenv('PHP_PEAR_TEST_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); -} - -// Default for temp_dir -if (getenv('PHP_PEAR_TEMP_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'temp'); -} - -// Default for cache_dir -if (getenv('PHP_PEAR_CACHE_DIR')) { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'cache'); -} - -// Default for download_dir -if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'download'); -} - -// Default for php_bin -if (getenv('PHP_PEAR_PHP_BIN')) { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. - DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); -} - -// Default for verbose -if (getenv('PHP_PEAR_VERBOSE')) { - define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); -} else { - define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); -} - -// Default for preferred_state -if (getenv('PHP_PEAR_PREFERRED_STATE')) { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); -} else { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); -} - -// Default for umask -if (getenv('PHP_PEAR_UMASK')) { - define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); -} else { - define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); -} - -// Default for cache_ttl -if (getenv('PHP_PEAR_CACHE_TTL')) { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); -} - -// Default for sig_type -if (getenv('PHP_PEAR_SIG_TYPE')) { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); -} - -// Default for sig_bin -if (getenv('PHP_PEAR_SIG_BIN')) { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', - System::which( - 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); -} - -// Default for sig_keydir -if (getenv('PHP_PEAR_SIG_KEYDIR')) { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', - PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); -} - -/** - * This is a class for storing configuration data, keeping track of - * which are system-defined, user-defined or defaulted. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Config extends PEAR -{ - /** - * Array of config files used. - * - * @var array layer => config file - */ - var $files = array( - 'system' => '', - 'user' => '', - ); - - var $layers = array(); - - /** - * Configuration data, two-dimensional array where the first - * dimension is the config layer ('user', 'system' and 'default'), - * and the second dimension is keyname => value. - * - * The order in the first dimension is important! Earlier - * layers will shadow later ones when a config value is - * requested (if a 'user' value exists, it will be returned first, - * then 'system' and finally 'default'). - * - * @var array layer => array(keyname => value, ...) - */ - var $configuration = array( - 'user' => array(), - 'system' => array(), - 'default' => array(), - ); - - /** - * Configuration values that can be set for a channel - * - * All other configuration values can only have a global value - * @var array - * @access private - */ - var $_channelConfigInfo = array( - 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', - 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', - 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' - ); - - /** - * Channels that can be accessed - * @see setChannels() - * @var array - * @access private - */ - var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); - - /** - * This variable is used to control the directory values returned - * @see setInstallRoot(); - * @var string|false - * @access private - */ - var $_installRoot = false; - - /** - * If requested, this will always refer to the registry - * contained in php_dir - * @var PEAR_Registry - */ - var $_registry = array(); - - /** - * @var array - * @access private - */ - var $_regInitialized = array(); - - /** - * @var bool - * @access private - */ - var $_noRegistry = false; - - /** - * amount of errors found while parsing config - * @var integer - * @access private - */ - var $_errorsFound = 0; - var $_lastError = null; - - /** - * Information about the configuration data. Stores the type, - * default value and a documentation string for each configuration - * value. - * - * @var array layer => array(infotype => value, ...) - */ - var $configuration_info = array( - // Channels/Internet Access - 'default_channel' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default channel to use for all non explicit commands', - 'prompt' => 'Default Channel', - 'group' => 'Internet Access', - ), - 'preferred_mirror' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default server or mirror to use for channel actions', - 'prompt' => 'Default Channel Mirror', - 'group' => 'Internet Access', - ), - 'remote_config' => array( - 'type' => 'password', - 'default' => '', - 'doc' => 'ftp url of remote configuration file to use for synchronized install', - 'prompt' => 'Remote Configuration File', - 'group' => 'Internet Access', - ), - 'auto_discover' => array( - 'type' => 'integer', - 'default' => 0, - 'doc' => 'whether to automatically discover new channels', - 'prompt' => 'Auto-discover new Channels', - 'group' => 'Internet Access', - ), - // Internet Access - 'master_server' => array( - 'type' => 'string', - 'default' => 'pear.php.net', - 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', - 'prompt' => 'PEAR server [DEPRECATED]', - 'group' => 'Internet Access', - ), - 'http_proxy' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, - 'doc' => 'HTTP proxy (host:port) to use when downloading packages', - 'prompt' => 'HTTP Proxy Server Address', - 'group' => 'Internet Access', - ), - // File Locations - 'php_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, - 'doc' => 'directory where .php files are installed', - 'prompt' => 'PEAR directory', - 'group' => 'File Locations', - ), - 'ext_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, - 'doc' => 'directory where loadable extensions are installed', - 'prompt' => 'PHP extension directory', - 'group' => 'File Locations', - ), - 'doc_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, - 'doc' => 'directory where documentation is installed', - 'prompt' => 'PEAR documentation directory', - 'group' => 'File Locations', - ), - 'bin_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, - 'doc' => 'directory where executables are installed', - 'prompt' => 'PEAR executables directory', - 'group' => 'File Locations', - ), - 'data_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, - 'doc' => 'directory where data files are installed', - 'prompt' => 'PEAR data directory', - 'group' => 'File Locations (Advanced)', - ), - 'cfg_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, - 'doc' => 'directory where modifiable configuration files are installed', - 'prompt' => 'PEAR configuration file directory', - 'group' => 'File Locations (Advanced)', - ), - 'www_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, - 'doc' => 'directory where www frontend files (html/js) are installed', - 'prompt' => 'PEAR www files directory', - 'group' => 'File Locations (Advanced)', - ), - 'test_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, - 'doc' => 'directory where regression tests are installed', - 'prompt' => 'PEAR test directory', - 'group' => 'File Locations (Advanced)', - ), - 'cache_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, - 'doc' => 'directory which is used for web service cache', - 'prompt' => 'PEAR Installer cache directory', - 'group' => 'File Locations (Advanced)', - ), - 'temp_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, - 'doc' => 'directory which is used for all temp files', - 'prompt' => 'PEAR Installer temp directory', - 'group' => 'File Locations (Advanced)', - ), - 'download_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, - 'doc' => 'directory which is used for all downloaded files', - 'prompt' => 'PEAR Installer download directory', - 'group' => 'File Locations (Advanced)', - ), - 'php_bin' => array( - 'type' => 'file', - 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, - 'doc' => 'PHP CLI/CGI binary for executing scripts', - 'prompt' => 'PHP CLI/CGI binary', - 'group' => 'File Locations (Advanced)', - ), - 'php_prefix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-prefix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_suffix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-suffix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_ini' => array( - 'type' => 'file', - 'default' => '', - 'doc' => 'location of php.ini in which to enable PECL extensions on install', - 'prompt' => 'php.ini location', - 'group' => 'File Locations (Advanced)', - ), - // Maintainers - 'username' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '(maintainers) your PEAR account name', - 'prompt' => 'PEAR username (for maintainers)', - 'group' => 'Maintainers', - ), - 'password' => array( - 'type' => 'password', - 'default' => '', - 'doc' => '(maintainers) your PEAR account password', - 'prompt' => 'PEAR password (for maintainers)', - 'group' => 'Maintainers', - ), - // Advanced - 'verbose' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, - 'doc' => 'verbosity level -0: really quiet -1: somewhat quiet -2: verbose -3: debug', - 'prompt' => 'Debug Log Level', - 'group' => 'Advanced', - ), - 'preferred_state' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, - 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', - 'valid_set' => array( - 'stable', 'beta', 'alpha', 'devel', 'snapshot'), - 'prompt' => 'Preferred Package State', - 'group' => 'Advanced', - ), - 'umask' => array( - 'type' => 'mask', - 'default' => PEAR_CONFIG_DEFAULT_UMASK, - 'doc' => 'umask used when creating files (Unix-like systems only)', - 'prompt' => 'Unix file mask', - 'group' => 'Advanced', - ), - 'cache_ttl' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, - 'doc' => 'amount of secs where the local cache is used and not updated', - 'prompt' => 'Cache TimeToLive', - 'group' => 'Advanced', - ), - 'sig_type' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, - 'doc' => 'which package signature mechanism to use', - 'valid_set' => array('gpg'), - 'prompt' => 'Package Signature Type', - 'group' => 'Maintainers', - ), - 'sig_bin' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, - 'doc' => 'which package signature mechanism to use', - 'prompt' => 'Signature Handling Program', - 'group' => 'Maintainers', - ), - 'sig_keyid' => array( - 'type' => 'string', - 'default' => '', - 'doc' => 'which key to use for signing with', - 'prompt' => 'Signature Key Id', - 'group' => 'Maintainers', - ), - 'sig_keydir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, - 'doc' => 'directory where signature keys are located', - 'prompt' => 'Signature Key Directory', - 'group' => 'Maintainers', - ), - // __channels is reserved - used for channel-specific configuration - ); - - /** - * Constructor. - * - * @param string file to read user-defined options from - * @param string file to read system-wide defaults from - * @param bool determines whether a registry object "follows" - * the value of php_dir (is automatically created - * and moved when php_dir is changed) - * @param bool if true, fails if configuration files cannot be loaded - * - * @access public - * - * @see PEAR_Config::singleton - */ - function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, - $strict = true) - { - $this->PEAR(); - PEAR_Installer_Role::initializeConfig($this); - $sl = DIRECTORY_SEPARATOR; - if (empty($user_file)) { - if (OS_WINDOWS) { - $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; - } else { - $user_file = getenv('HOME') . $sl . '.pearrc'; - } - } - - if (empty($system_file)) { - $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; - if (OS_WINDOWS) { - $system_file .= 'pearsys.ini'; - } else { - $system_file .= 'pear.conf'; - } - } - - $this->layers = array_keys($this->configuration); - $this->files['user'] = $user_file; - $this->files['system'] = $system_file; - if ($user_file && file_exists($user_file)) { - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->readConfigFile($user_file, 'user', $strict); - $this->popErrorHandling(); - if ($this->_errorsFound > 0) { - return; - } - } - - if ($system_file && @file_exists($system_file)) { - $this->mergeConfigFile($system_file, false, 'system', $strict); - if ($this->_errorsFound > 0) { - return; - } - - } - - if (!$ftp_file) { - $ftp_file = $this->get('remote_config'); - } - - if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { - $this->readFTPConfigFile($ftp_file); - } - - foreach ($this->configuration_info as $key => $info) { - $this->configuration['default'][$key] = $info['default']; - } - - $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); - $this->_registry['default']->setConfig($this, false); - $this->_regInitialized['default'] = false; - //$GLOBALS['_PEAR_Config_instance'] = &$this; - } - - /** - * Return the default locations of user and system configuration files - * @static - */ - function getDefaultConfigFiles() - { - $sl = DIRECTORY_SEPARATOR; - if (OS_WINDOWS) { - return array( - 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' - ); - } - - return array( - 'user' => getenv('HOME') . $sl . '.pearrc', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' - ); - } - - /** - * Static singleton method. If you want to keep only one instance - * of this class in use, this method will give you a reference to - * the last created PEAR_Config object if one exists, or create a - * new object. - * - * @param string (optional) file to read user-defined options from - * @param string (optional) file to read system-wide defaults from - * - * @return object an existing or new PEAR_Config instance - * - * @access public - * - * @see PEAR_Config::PEAR_Config - */ - function &singleton($user_file = '', $system_file = '', $strict = true) - { - if (is_object($GLOBALS['_PEAR_Config_instance'])) { - return $GLOBALS['_PEAR_Config_instance']; - } - - $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); - if ($t_conf->_errorsFound > 0) { - return $t_conf->lastError; - } - - $GLOBALS['_PEAR_Config_instance'] = &$t_conf; - return $GLOBALS['_PEAR_Config_instance']; - } - - /** - * Determine whether any configuration files have been detected, and whether a - * registry object can be retrieved from this configuration. - * @return bool - * @since PEAR 1.4.0a1 - */ - function validConfiguration() - { - if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { - return true; - } - - return false; - } - - /** - * Reads configuration data from a file. All existing values in - * the config layer are discarded and replaced with data from the - * file. - * @param string file to read from, if NULL or not specified, the - * last-used file for the same layer (second param) is used - * @param string config layer to insert data into ('user' or 'system') - * @return bool TRUE on success or a PEAR error on failure - */ - function readConfigFile($file = null, $layer = 'user', $strict = true) - { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; - } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; - } - - $this->files[$layer] = $file; - $this->_decodeInput($data); - $this->configuration[$layer] = $data; - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - } - return true; - } - - /** - * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini - * @return true|PEAR_Error - */ - function readFTPConfigFile($path) - { - do { // poor man's try - if (!class_exists('PEAR_FTP')) { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { - require_once 'PEAR/FTP.php'; - } - } - - if (!class_exists('PEAR_FTP')) { - return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); - } - - $this->_ftp = &new PEAR_FTP; - $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); - $e = $this->_ftp->init($path); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - $tmp = System::mktemp('-d'); - PEAR_Common::addTempFile($tmp); - $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . - 'pear.ini', false, FTP_BINARY); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); - $this->_ftp->disconnect(); - $this->_ftp->popErrorHandling(); - $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; - $e = $this->readConfigFile(null, 'ftp'); - if (PEAR::isError($e)) { - return $e; - } - - $fail = array(); - foreach ($this->configuration_info as $key => $val) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - // any directory configs must be set for this to work - if (!isset($this->configuration['ftp'][$key])) { - $fail[] = $key; - } - } - } - - if (!count($fail)) { - return true; - } - - $fail = '"' . implode('", "', $fail) . '"'; - unset($this->files['ftp']); - unset($this->configuration['ftp']); - return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . - 'directory configuration variables. These variables were not set: ' . - $fail); - } while (false); // poor man's catch - unset($this->files['ftp']); - return PEAR::raiseError('no remote host specified'); - } - - /** - * Reads the existing configurations and creates the _channels array from it - */ - function _setupChannels() - { - $set = array_flip(array_values($this->_channels)); - foreach ($this->configuration as $layer => $data) { - $i = 1000; - if (isset($data['__channels']) && is_array($data['__channels'])) { - foreach ($data['__channels'] as $channel => $info) { - $set[$channel] = $i++; - } - } - } - $this->_channels = array_values(array_flip($set)); - $this->setChannels($this->_channels); - } - - function deleteChannel($channel) - { - $ch = strtolower($channel); - foreach ($this->configuration as $layer => $data) { - if (isset($data['__channels']) && isset($data['__channels'][$ch])) { - unset($this->configuration[$layer]['__channels'][$ch]); - } - } - - $this->_channels = array_flip($this->_channels); - unset($this->_channels[$ch]); - $this->_channels = array_flip($this->_channels); - } - - /** - * Merges data into a config layer from a file. Does the same - * thing as readConfigFile, except it does not replace all - * existing values in the config layer. - * @param string file to read from - * @param bool whether to overwrite existing data (default TRUE) - * @param string config layer to insert data into ('user' or 'system') - * @param string if true, errors are returned if file opening fails - * @return bool TRUE on success or a PEAR error on failure - */ - function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) - { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; - } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; - } - - $this->_decodeInput($data); - if ($override) { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); - } else { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); - } - - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - } - return true; - } - - /** - * @param array - * @param array - * @return array - * @static - */ - function arrayMergeRecursive($arr2, $arr1) - { - $ret = array(); - foreach ($arr2 as $key => $data) { - if (!isset($arr1[$key])) { - $ret[$key] = $data; - unset($arr1[$key]); - continue; - } - if (is_array($data)) { - if (!is_array($arr1[$key])) { - $ret[$key] = $arr1[$key]; - unset($arr1[$key]); - continue; - } - $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); - unset($arr1[$key]); - } - } - - return array_merge($ret, $arr1); - } - - /** - * Writes data into a config layer from a file. - * - * @param string|null file to read from, or null for default - * @param string config layer to insert data into ('user' or - * 'system') - * @param string|null data to write to config file or null for internal data [DEPRECATED] - * @return bool TRUE on success or a PEAR error on failure - */ - function writeConfigFile($file = null, $layer = 'user', $data = null) - { - $this->_lazyChannelSetup($layer); - if ($layer == 'both' || $layer == 'all') { - foreach ($this->files as $type => $file) { - $err = $this->writeConfigFile($file, $type, $data); - if (PEAR::isError($err)) { - return $err; - } - } - return true; - } - - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config file type `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = ($data === null) ? $this->configuration[$layer] : $data; - $this->_encodeOutput($data); - $opt = array('-p', dirname($file)); - if (!@System::mkDir($opt)) { - return $this->raiseError("could not create directory: " . dirname($file)); - } - - if (file_exists($file) && is_file($file) && !is_writeable($file)) { - return $this->raiseError("no write access to $file!"); - } - - $fp = @fopen($file, "w"); - if (!$fp) { - return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); - } - - $contents = "#PEAR_Config 0.9\n" . serialize($data); - if (!@fwrite($fp, $contents)) { - return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); - } - return true; - } - - /** - * Reads configuration data from a file and returns the parsed data - * in an array. - * - * @param string file to read from - * @return array configuration data or a PEAR error on failure - * @access private - */ - function _readConfigDataFrom($file) - { - $fp = false; - if (file_exists($file)) { - $fp = @fopen($file, "r"); - } - - if (!$fp) { - return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); - } - - $size = filesize($file); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fclose($fp); - $contents = file_get_contents($file); - if (empty($contents)) { - return $this->raiseError('Configuration file "' . $file . '" is empty'); - } - - set_magic_quotes_runtime($rt); - - $version = false; - if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { - $version = $matches[1]; - $contents = substr($contents, strlen($matches[0])); - } else { - // Museum config file - if (substr($contents,0,2) == 'a:') { - $version = '0.1'; - } - } - - if ($version && version_compare("$version", '1', '<')) { - // no '@', it is possible that unserialize - // raises a notice but it seems to block IO to - // STDOUT if a '@' is used and a notice is raise - $data = unserialize($contents); - - if (!is_array($data) && !$data) { - if ($contents == serialize(false)) { - $data = array(); - } else { - $err = $this->raiseError("PEAR_Config: bad data in $file"); - return $err; - } - } - if (!is_array($data)) { - if (strlen(trim($contents)) > 0) { - $error = "PEAR_Config: bad data in $file"; - $err = $this->raiseError($error); - return $err; - } - - $data = array(); - } - // add parsing of newer formats here... - } else { - $err = $this->raiseError("$file: unknown version `$version'"); - return $err; - } - - return $data; - } - - /** - * Gets the file used for storing the config for a layer - * - * @param string $layer 'user' or 'system' - */ - function getConfFile($layer) - { - return $this->files[$layer]; - } - - /** - * @param string Configuration class name, used for detecting duplicate calls - * @param array information on a role as parsed from its xml file - * @return true|PEAR_Error - * @access private - */ - function _addConfigVars($class, $vars) - { - static $called = array(); - if (isset($called[$class])) { - return; - } - - $called[$class] = 1; - if (count($vars) > 3) { - return $this->raiseError('Roles can only define 3 new config variables or less'); - } - - foreach ($vars as $name => $var) { - if (!is_array($var)) { - return $this->raiseError('Configuration information must be an array'); - } - - if (!isset($var['type'])) { - return $this->raiseError('Configuration information must contain a type'); - } elseif (!in_array($var['type'], - array('string', 'mask', 'password', 'directory', 'file', 'set'))) { - return $this->raiseError( - 'Configuration type must be one of directory, file, string, ' . - 'mask, set, or password'); - } - if (!isset($var['default'])) { - return $this->raiseError( - 'Configuration information must contain a default value ("default" index)'); - } - - if (is_array($var['default'])) { - $real_default = ''; - foreach ($var['default'] as $config_var => $val) { - if (strpos($config_var, 'text') === 0) { - $real_default .= $val; - } elseif (strpos($config_var, 'constant') === 0) { - if (!defined($val)) { - return $this->raiseError( - 'Unknown constant "' . $val . '" requested in ' . - 'default value for configuration variable "' . - $name . '"'); - } - - $real_default .= constant($val); - } elseif (isset($this->configuration_info[$config_var])) { - $real_default .= - $this->configuration_info[$config_var]['default']; - } else { - return $this->raiseError( - 'Unknown request for "' . $config_var . '" value in ' . - 'default value for configuration variable "' . - $name . '"'); - } - } - $var['default'] = $real_default; - } - - if ($var['type'] == 'integer') { - $var['default'] = (integer) $var['default']; - } - - if (!isset($var['doc'])) { - return $this->raiseError( - 'Configuration information must contain a summary ("doc" index)'); - } - - if (!isset($var['prompt'])) { - return $this->raiseError( - 'Configuration information must contain a simple prompt ("prompt" index)'); - } - - if (!isset($var['group'])) { - return $this->raiseError( - 'Configuration information must contain a simple group ("group" index)'); - } - - if (isset($this->configuration_info[$name])) { - return $this->raiseError('Configuration variable "' . $name . - '" already exists'); - } - - $this->configuration_info[$name] = $var; - // fix bug #7351: setting custom config variable in a channel fails - $this->_channelConfigInfo[] = $name; - } - - return true; - } - - /** - * Encodes/scrambles configuration data before writing to files. - * Currently, 'password' values will be base64-encoded as to avoid - * that people spot cleartext passwords by accident. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private - */ - function _encodeOutput(&$data) - { - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_encodeOutput($data['__channels'][$channel]); - } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - // we base64-encode passwords so they are at least - // not shown in plain by accident - case 'password': { - $data[$key] = base64_encode($data[$key]); - break; - } - case 'mask': { - $data[$key] = octdec($data[$key]); - break; - } - } - } - - return true; - } - - /** - * Decodes/unscrambles configuration data after reading from files. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private - * - * @see PEAR_Config::_encodeOutput - */ - function _decodeInput(&$data) - { - if (!is_array($data)) { - return true; - } - - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_decodeInput($data['__channels'][$channel]); - } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - case 'password': { - $data[$key] = base64_decode($data[$key]); - break; - } - case 'mask': { - $data[$key] = decoct($data[$key]); - break; - } - } - } - - return true; - } - - /** - * Retrieve the default channel. - * - * On startup, channels are not initialized, so if the default channel is not - * pear.php.net, then initialize the config. - * @param string registry layer - * @return string|false - */ - function getDefaultChannel($layer = null) - { - $ret = false; - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - break; - } - } - } elseif (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - } - - if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { - $ret = 'pecl.php.net'; - } - - if ($ret) { - if ($ret != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - - return $ret; - } - - return PEAR_CONFIG_DEFAULT_CHANNEL; - } - - /** - * Returns a configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access public - */ - function get($key, $layer = null, $channel = false) - { - if (!isset($this->configuration_info[$key])) { - return null; - } - - if ($key == '__channels') { - return null; - } - - if ($key == 'default_channel') { - return $this->getDefaultChannel($layer); - } - - if (!$channel) { - $channel = $this->getDefaultChannel(); - } elseif ($channel != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - $channel = strtolower($channel); - - $test = (in_array($key, $this->_channelConfigInfo)) ? - $this->_getChannelValue($key, $layer, $channel) : - null; - if ($test !== null) { - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - return $test; - } - - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } - - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } - } - } - return $test; - } - } - } elseif (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } - - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } - } - } - - return $test; - } - - return null; - } - - /** - * Returns a channel-specific configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access private - */ - function _getChannelValue($key, $layer, $channel) - { - if ($key == '__channels' || $channel == 'pear.php.net') { - return null; - } - - $ret = null; - if ($layer === null) { - foreach ($this->layers as $ilayer) { - if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; - break; - } - } - } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$layer]['__channels'][$channel][$key]; - } - - if ($key != 'preferred_mirror') { - return $ret; - } - - - if ($ret !== null) { - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } - - if (!$chan->getMirror($ret) && $chan->getName() != $ret) { - return $channel; // mirror does not exist - } - } - - return $ret; - } - - if ($channel != $this->getDefaultChannel($layer)) { - return $channel; // we must use the channel name as the preferred mirror - // if the user has not chosen an alternate - } - - return $this->getDefaultChannel($layer); - } - - /** - * Set a config value in a specific layer (defaults to 'user'). - * Enforces the types defined in the configuration_info array. An - * integer config variable will be cast to int, and a set config - * variable will be validated against its legal values. - * - * @param string config key - * @param string config value - * @param string (optional) config layer - * @param string channel to set this value for, or null for global value - * @return bool TRUE on success, FALSE on failure - */ - function set($key, $value, $layer = 'user', $channel = false) - { - if ($key == '__channels') { - return false; - } - - if (!isset($this->configuration[$layer])) { - return false; - } - - if ($key == 'default_channel') { - // can only set this value globally - $channel = 'pear.php.net'; - if ($value != 'pear.php.net') { - $this->_lazyChannelSetup($layer); - } - } - - if ($key == 'preferred_mirror') { - if ($channel == '__uri') { - return false; // can't set the __uri pseudo-channel's mirror - } - - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); - if (PEAR::isError($chan)) { - return false; - } - - if (!$chan->getMirror($value) && $chan->getName() != $value) { - return false; // mirror does not exist - } - } - } - - if (!isset($this->configuration_info[$key])) { - return false; - } - - extract($this->configuration_info[$key]); - switch ($type) { - case 'integer': - $value = (int)$value; - break; - case 'set': { - // If a valid_set is specified, require the value to - // be in the set. If there is no valid_set, accept - // any value. - if ($valid_set) { - reset($valid_set); - if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || - (key($valid_set) !== 0 && empty($valid_set[$value]))) - { - return false; - } - } - break; - } - } - - if (!$channel) { - $channel = $this->get('default_channel', null, 'pear.php.net'); - } - - if (!in_array($channel, $this->_channels)) { - $this->_lazyChannelSetup($layer); - $reg = &$this->getRegistry($layer); - if ($reg) { - $channel = $reg->channelName($channel); - } - - if (!in_array($channel, $this->_channels)) { - return false; - } - } - - if ($channel != 'pear.php.net') { - if (in_array($key, $this->_channelConfigInfo)) { - $this->configuration[$layer]['__channels'][$channel][$key] = $value; - return true; - } - - return false; - } - - if ($key == 'default_channel') { - if (!isset($reg)) { - $reg = &$this->getRegistry($layer); - if (!$reg) { - $reg = &$this->getRegistry(); - } - } - - if ($reg) { - $value = $reg->channelName($value); - } - - if (!$value) { - return false; - } - } - - $this->configuration[$layer][$key] = $value; - if ($key == 'php_dir' && !$this->_noRegistry) { - if (!isset($this->_registry[$layer]) || - $value != $this->_registry[$layer]->install_dir) { - $this->_registry[$layer] = &new PEAR_Registry($value); - $this->_regInitialized[$layer] = false; - $this->_registry[$layer]->setConfig($this, false); - } - } - - return true; - } - - function _lazyChannelSetup($uselayer = false) - { - if ($this->_noRegistry) { - return; - } - - $merge = false; - foreach ($this->_registry as $layer => $p) { - if ($uselayer && $uselayer != $layer) { - continue; - } - - if (!$this->_regInitialized[$layer]) { - if ($layer == 'default' && isset($this->_registry['user']) || - isset($this->_registry['system'])) { - // only use the default registry if there are no alternatives - continue; - } - - if (!is_object($this->_registry[$layer])) { - if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - return; - } - } - - $this->setChannels($this->_registry[$layer]->listChannels(), $merge); - $this->_regInitialized[$layer] = true; - $merge = true; - } - } - } - - /** - * Set the list of channels. - * - * This should be set via a call to {@link PEAR_Registry::listChannels()} - * @param array - * @param bool - * @return bool success of operation - */ - function setChannels($channels, $merge = false) - { - if (!is_array($channels)) { - return false; - } - - if ($merge) { - $this->_channels = array_merge($this->_channels, $channels); - } else { - $this->_channels = $channels; - } - - foreach ($channels as $channel) { - $channel = strtolower($channel); - if ($channel == 'pear.php.net') { - continue; - } - - foreach ($this->layers as $layer) { - if (!isset($this->configuration[$layer]['__channels'])) { - $this->configuration[$layer]['__channels'] = array(); - } - if (!isset($this->configuration[$layer]['__channels'][$channel]) - || !is_array($this->configuration[$layer]['__channels'][$channel])) { - $this->configuration[$layer]['__channels'][$channel] = array(); - } - } - } - - return true; - } - - /** - * Get the type of a config value. - * - * @param string config key - * - * @return string type, one of "string", "integer", "file", - * "directory", "set" or "password". - * - * @access public - * - */ - function getType($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['type']; - } - return false; - } - - /** - * Get the documentation for a config value. - * - * @param string config key - * @return string documentation string - * - * @access public - * - */ - function getDocs($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['doc']; - } - - return false; - } - - /** - * Get the short documentation for a config value. - * - * @param string config key - * @return string short documentation string - * - * @access public - * - */ - function getPrompt($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['prompt']; - } - - return false; - } - - /** - * Get the parameter group for a config key. - * - * @param string config key - * @return string parameter group - * - * @access public - * - */ - function getGroup($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['group']; - } - - return false; - } - - /** - * Get the list of parameter groups. - * - * @return array list of parameter groups - * - * @access public - * - */ - function getGroups() - { - $tmp = array(); - foreach ($this->configuration_info as $key => $info) { - $tmp[$info['group']] = 1; - } - - return array_keys($tmp); - } - - /** - * Get the list of the parameters in a group. - * - * @param string $group parameter group - * @return array list of parameters in $group - * - * @access public - * - */ - function getGroupKeys($group) - { - $keys = array(); - foreach ($this->configuration_info as $key => $info) { - if ($info['group'] == $group) { - $keys[] = $key; - } - } - - return $keys; - } - - /** - * Get the list of allowed set values for a config value. Returns - * NULL for config values that are not sets. - * - * @param string config key - * @return array enumerated array of set values, or NULL if the - * config key is unknown or not a set - * - * @access public - * - */ - function getSetValues($key) - { - if (isset($this->configuration_info[$key]) && - isset($this->configuration_info[$key]['type']) && - $this->configuration_info[$key]['type'] == 'set') - { - $valid_set = $this->configuration_info[$key]['valid_set']; - reset($valid_set); - if (key($valid_set) === 0) { - return $valid_set; - } - - return array_keys($valid_set); - } - - return null; - } - - /** - * Get all the current config keys. - * - * @return array simple array of config keys - * - * @access public - */ - function getKeys() - { - $keys = array(); - foreach ($this->layers as $layer) { - $test = $this->configuration[$layer]; - if (isset($test['__channels'])) { - foreach ($test['__channels'] as $channel => $configs) { - $keys = array_merge($keys, $configs); - } - } - - unset($test['__channels']); - $keys = array_merge($keys, $test); - - } - return array_keys($keys); - } - - /** - * Remove the a config key from a specific config layer. - * - * @param string config key - * @param string (optional) config layer - * @param string (optional) channel (defaults to default channel) - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function remove($key, $layer = 'user', $channel = null) - { - if ($channel === null) { - $channel = $this->getDefaultChannel(); - } - - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - unset($this->configuration[$layer]['__channels'][$channel][$key]); - return true; - } - } - - if (isset($this->configuration[$layer][$key])) { - unset($this->configuration[$layer][$key]); - return true; - } - - return false; - } - - /** - * Temporarily remove an entire config layer. USE WITH CARE! - * - * @param string config key - * @param string (optional) config layer - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function removeLayer($layer) - { - if (isset($this->configuration[$layer])) { - $this->configuration[$layer] = array(); - return true; - } - - return false; - } - - /** - * Stores configuration data in a layer. - * - * @param string config layer to store - * @return bool TRUE on success, or PEAR error on failure - * - * @access public - */ - function store($layer = 'user', $data = null) - { - return $this->writeConfigFile(null, $layer, $data); - } - - /** - * Tells what config layer that gets to define a key. - * - * @param string config key - * @param boolean return the defining channel - * - * @return string|array the config layer, or an empty string if not found. - * - * if $returnchannel, the return is an array array('layer' => layername, - * 'channel' => channelname), or an empty string if not found - * - * @access public - */ - function definedBy($key, $returnchannel = false) - { - foreach ($this->layers as $layer) { - $channel = $this->getDefaultChannel(); - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => $channel); - } - return $layer; - } - } - - if (isset($this->configuration[$layer][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => 'pear.php.net'); - } - return $layer; - } - } - - return ''; - } - - /** - * Tells whether a given key exists as a config value. - * - * @param string config key - * @return bool whether exists in this object - * - * @access public - */ - function isDefined($key) - { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - return true; - } - } - - return false; - } - - /** - * Tells whether a given config layer exists. - * - * @param string config layer - * @return bool whether exists in this object - * - * @access public - */ - function isDefinedLayer($layer) - { - return isset($this->configuration[$layer]); - } - - /** - * Returns the layers defined (except the 'default' one) - * - * @return array of the defined layers - */ - function getLayers() - { - $cf = $this->configuration; - unset($cf['default']); - return array_keys($cf); - } - - function apiVersion() - { - return '1.1'; - } - - /** - * @return PEAR_Registry - */ - function &getRegistry($use = null) - { - $layer = $use === null ? 'user' : $use; - if (isset($this->_registry[$layer])) { - return $this->_registry[$layer]; - } elseif ($use === null && isset($this->_registry['system'])) { - return $this->_registry['system']; - } elseif ($use === null && isset($this->_registry['default'])) { - return $this->_registry['default']; - } elseif ($use) { - $a = false; - return $a; - } - - // only go here if null was passed in - echo "CRITICAL ERROR: Registry could not be initialized from any value"; - exit(1); - } - - /** - * This is to allow customization like the use of installroot - * @param PEAR_Registry - * @return bool - */ - function setRegistry(&$reg, $layer = 'user') - { - if ($this->_noRegistry) { - return false; - } - - if (!in_array($layer, array('user', 'system'))) { - return false; - } - - $this->_registry[$layer] = &$reg; - if (is_object($reg)) { - $this->_registry[$layer]->setConfig($this, false); - } - - return true; - } - - function noRegistry() - { - $this->_noRegistry = true; - } - - /** - * @return PEAR_REST - */ - function &getREST($version, $options = array()) - { - $version = str_replace('.', '', $version); - if (!class_exists($class = 'PEAR_REST_' . $version)) { - require_once 'PEAR/REST/' . $version . '.php'; - } - - $remote = &new $class($this, $options); - return $remote; - } - - /** - * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a - * remote configuration file has been specified - * @return PEAR_FTP|false - */ - function &getFTP() - { - if (isset($this->_ftp)) { - return $this->_ftp; - } - - $a = false; - return $a; - } - - function _prependPath($path, $prepend) - { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; - } - } - return $path; - } - - /** - * @param string|false installation directory to prepend to all _dir variables, or false to - * disable - */ - function setInstallRoot($root) - { - if (substr($root, -1) == DIRECTORY_SEPARATOR) { - $root = substr($root, 0, -1); - } - $old = $this->_installRoot; - $this->_installRoot = $root; - if (($old != $root) && !$this->_noRegistry) { - foreach (array_keys($this->_registry) as $layer) { - if ($layer == 'ftp' || !isset($this->_registry[$layer])) { - continue; - } - $this->_registry[$layer] = - &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } - } - } -} -PEAR-1.9.0/PEAR/DependencyDB.php100664 764 764 57256 100664 11071 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: DependencyDB.php 286686 2009-08-02 17:38:57Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Needed for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Config.php'; - -$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); -/** - * Track dependency relationships between installed packages - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_DependencyDB -{ - // {{{ properties - - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Config - * @access private - */ - var $_config; - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Registry - * @access private - */ - var $_registry; - /** - * Filename of the dependency DB (usually .depdb) - * @var string - * @access private - */ - var $_depdb = false; - /** - * File name of the lockfile (usually .depdblock) - * @var string - * @access private - */ - var $_lockfile = false; - /** - * Open file resource for locking the lockfile - * @var resource|false - * @access private - */ - var $_lockFp = false; - /** - * API version of this class, used to validate a file on-disk - * @var string - * @access private - */ - var $_version = '1.0'; - /** - * Cached dependency database file - * @var array|null - * @access private - */ - var $_cache; - - // }}} - // {{{ & singleton() - - /** - * Get a raw dependency database. Calls setConfig() and assertDepsDB() - * @param PEAR_Config - * @param string|false full path to the dependency database, or false to use default - * @return PEAR_DependencyDB|PEAR_Error - * @static - */ - function &singleton(&$config, $depdb = false) - { - $phpdir = $config->get('php_dir', null, 'pear.php.net'); - if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { - $a = new PEAR_DependencyDB; - $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; - $a->setConfig($config, $depdb); - $e = $a->assertDepsDB(); - if (PEAR::isError($e)) { - return $e; - } - } - - return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; - } - - /** - * Set up the registry/location of dependency DB - * @param PEAR_Config|false - * @param string|false full path to the dependency database, or false to use default - */ - function setConfig(&$config, $depdb = false) - { - if (!$config) { - $this->_config = &PEAR_Config::singleton(); - } else { - $this->_config = &$config; - } - - $this->_registry = &$this->_config->getRegistry(); - if (!$depdb) { - $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'; - } else { - $this->_depdb = $depdb; - } - - $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; - } - // }}} - - function hasWriteAccess() - { - if (!file_exists($this->_depdb)) { - $dir = $this->_depdb; - while ($dir && $dir != '.') { - $dir = dirname($dir); // cd .. - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - } - - return false; - } - - return is_writeable($this->_depdb); - } - - // {{{ assertDepsDB() - - /** - * Create the dependency database, if it doesn't exist. Error if the database is - * newer than the code reading it. - * @return void|PEAR_Error - */ - function assertDepsDB() - { - if (!is_file($this->_depdb)) { - $this->rebuildDB(); - return; - } - - $depdb = $this->_getDepDB(); - // Datatype format has been changed, rebuild the Deps DB - if ($depdb['_version'] < $this->_version) { - $this->rebuildDB(); - } - - if ($depdb['_version']{0} > $this->_version{0}) { - return PEAR::raiseError('Dependency database is version ' . - $depdb['_version'] . ', and we are version ' . - $this->_version . ', cannot continue'); - } - } - - /** - * Get a list of installed packages that depend on this package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependentPackages(&$pkg) - { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (isset($data['packages'][$channel][$package])) { - return $data['packages'][$channel][$package]; - } - - return false; - } - - /** - * Get a list of the actual dependencies of installed packages that depend on - * a package. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependentPackageDependencies(&$pkg) - { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $depend = $this->getDependentPackages($pkg); - if (!$depend) { - return false; - } - - $dependencies = array(); - foreach ($depend as $info) { - $temp = $this->getDependencies($info); - foreach ($temp as $dep) { - if ( - isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && - strtolower($dep['dep']['channel']) == $channel && - strtolower($dep['dep']['name']) == $package - ) { - if (!isset($dependencies[$info['channel']])) { - $dependencies[$info['channel']] = array(); - } - - if (!isset($dependencies[$info['channel']][$info['package']])) { - $dependencies[$info['channel']][$info['package']] = array(); - } - $dependencies[$info['channel']][$info['package']][] = $dep; - } - } - } - - return $dependencies; - } - - /** - * Get a list of dependencies of this installed package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependencies(&$pkg) - { - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $data = $this->_getDepDB(); - if (isset($data['dependencies'][$channel][$package])) { - return $data['dependencies'][$channel][$package]; - } - - return false; - } - - /** - * Determine whether $parent depends on $child, near or deep - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 - */ - function dependsOn($parent, $child) - { - $c = array(); - $this->_getDepDB(); - return $this->_dependsOn($parent, $child, $c); - } - - function _dependsOn($parent, $child, &$checked) - { - if (is_object($parent)) { - $channel = strtolower($parent->getChannel()); - $package = strtolower($parent->getPackage()); - } else { - $channel = strtolower($parent['channel']); - $package = strtolower($parent['package']); - } - - if (is_object($child)) { - $depchannel = strtolower($child->getChannel()); - $deppackage = strtolower($child->getPackage()); - } else { - $depchannel = strtolower($child['channel']); - $deppackage = strtolower($child['package']); - } - - if (isset($checked[$channel][$package][$depchannel][$deppackage])) { - return false; // avoid endless recursion - } - - $checked[$channel][$package][$depchannel][$deppackage] = true; - if (!isset($this->_cache['dependencies'][$channel][$package])) { - return false; - } - - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if (is_object($child)) { - if ($info['dep']['uri'] == $child->getURI()) { - return true; - } - } elseif (isset($child['uri'])) { - if ($info['dep']['uri'] == $child['uri']) { - return true; - } - } - return false; - } - - if (strtolower($info['dep']['channel']) == $depchannel && - strtolower($info['dep']['name']) == $deppackage) { - return true; - } - } - - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if ($this->_dependsOn(array( - 'uri' => $info['dep']['uri'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; - } - } else { - if ($this->_dependsOn(array( - 'channel' => $info['dep']['channel'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; - } - } - } - - return false; - } - - /** - * Register dependencies of a package that is being installed or upgraded - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 - */ - function installPackage(&$package) - { - $data = $this->_getDepDB(); - unset($this->_cache); - $this->_setPackageDeps($data, $package); - $this->_writeDepDB($data); - } - - /** - * Remove dependencies of a package that is being uninstalled, or upgraded. - * - * Upgraded packages first uninstall, then install - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have - * indices 'channel' and 'package' - */ - function uninstallPackage(&$pkg) - { - $data = $this->_getDepDB(); - unset($this->_cache); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (!isset($data['dependencies'][$channel][$package])) { - return true; - } - - foreach ($data['dependencies'][$channel][$package] as $dep) { - $found = false; - $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); - $depname = strtolower($dep['dep']['name']); - if (isset($data['packages'][$depchannel][$depname])) { - foreach ($data['packages'][$depchannel][$depname] as $i => $info) { - if ($info['channel'] == $channel && $info['package'] == $package) { - $found = true; - break; - } - } - } - - if ($found) { - unset($data['packages'][$depchannel][$depname][$i]); - if (!count($data['packages'][$depchannel][$depname])) { - unset($data['packages'][$depchannel][$depname]); - if (!count($data['packages'][$depchannel])) { - unset($data['packages'][$depchannel]); - } - } else { - $data['packages'][$depchannel][$depname] = - array_values($data['packages'][$depchannel][$depname]); - } - } - } - - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } - - if (!count($data['dependencies'])) { - unset($data['dependencies']); - } - - if (!count($data['packages'])) { - unset($data['packages']); - } - - $this->_writeDepDB($data); - } - - /** - * Rebuild the dependency DB by reading registry entries. - * @return true|PEAR_Error - */ - function rebuildDB() - { - $depdb = array('_version' => $this->_version); - if (!$this->hasWriteAccess()) { - // allow startup for read-only with older Registry - return $depdb; - } - - $packages = $this->_registry->listAllPackages(); - if (PEAR::isError($packages)) { - return $packages; - } - - foreach ($packages as $channel => $ps) { - foreach ($ps as $package) { - $package = $this->_registry->getPackage($package, $channel); - if (PEAR::isError($package)) { - return $package; - } - $this->_setPackageDeps($depdb, $package); - } - } - - $error = $this->_writeDepDB($depdb); - if (PEAR::isError($error)) { - return $error; - } - - $this->_cache = $depdb; - return true; - } - - /** - * Register usage of the dependency DB to prevent race conditions - * @param int one of the LOCK_* constants - * @return true|PEAR_Error - * @access private - */ - function _lock($mode = LOCK_EX) - { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->_lockFp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH) { - if (!file_exists($this->_lockfile)) { - touch($this->_lockfile); - } elseif (!is_file($this->_lockfile)) { - return PEAR::raiseError('could not create Dependency lock file, ' . - 'it exists and is not a regular file'); - } - $open_mode = 'r'; - } - - if (!is_resource($this->_lockFp)) { - $this->_lockFp = @fopen($this->_lockfile, $open_mode); - } - - if (!is_resource($this->_lockFp)) { - return PEAR::raiseError("could not create Dependency lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->_lockFp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); - } - - return true; - } - - /** - * Release usage of dependency DB - * @return true|PEAR_Error - * @access private - */ - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->_lockFp)) { - fclose($this->_lockFp); - } - $this->_lockFp = null; - return $ret; - } - - /** - * Load the dependency database from disk, or return the cache - * @return array|PEAR_Error - */ - function _getDepDB() - { - if (!$this->hasWriteAccess()) { - return array('_version' => $this->_version); - } - - if (isset($this->_cache)) { - return $this->_cache; - } - - if (!$fp = fopen($this->_depdb, 'r')) { - $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); - return $err; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - fclose($fp); - $data = unserialize(file_get_contents($this->_depdb)); - set_magic_quotes_runtime($rt); - $this->_cache = $data; - return $data; - } - - /** - * Write out the dependency database to disk - * @param array the database - * @return true|PEAR_Error - * @access private - */ - function _writeDepDB(&$deps) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - if (!$fp = fopen($this->_depdb, 'wb')) { - $this->_unlock(); - return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fwrite($fp, serialize($deps)); - set_magic_quotes_runtime($rt); - fclose($fp); - $this->_unlock(); - $this->_cache = $deps; - return true; - } - - /** - * Register all dependencies from a package in the dependencies database, in essence - * "installing" the package's dependency information - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @access private - */ - function _setPackageDeps(&$data, &$pkg) - { - $pkg->setConfig($this->_config); - if ($pkg->getPackagexmlVersion() == '1.0') { - $gen = &$pkg->getDefaultGenerator(); - $deps = $gen->dependenciesToV2(); - } else { - $deps = $pkg->getDeps(true); - } - - if (!$deps) { - return; - } - - if (!is_array($data)) { - $data = array(); - } - - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); - } - - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } - - $data['dependencies'][$channel][$package] = array(); - if (isset($deps['required']['package'])) { - if (!isset($deps['required']['package'][0])) { - $deps['required']['package'] = array($deps['required']['package']); - } - - foreach ($deps['required']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); - } - } - - if (isset($deps['optional']['package'])) { - if (!isset($deps['optional']['package'][0])) { - $deps['optional']['package'] = array($deps['optional']['package']); - } - - foreach ($deps['optional']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } - } - - if (isset($deps['required']['subpackage'])) { - if (!isset($deps['required']['subpackage'][0])) { - $deps['required']['subpackage'] = array($deps['required']['subpackage']); - } - - foreach ($deps['required']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); - } - } - - if (isset($deps['optional']['subpackage'])) { - if (!isset($deps['optional']['subpackage'][0])) { - $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); - } - - foreach ($deps['optional']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } - } - - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - foreach ($deps['group'] as $group) { - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - - foreach ($group['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } - - foreach ($group['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - } - } - - if ($data['dependencies'][$channel][$package] == array()) { - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } - } - } - - /** - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array the specific dependency - * @param required|optional whether this is a required or an optional dep - * @param string|false dependency group this dependency is from, or false for ordinary dep - */ - function _registerDep(&$data, &$pkg, $dep, $type, $group = false) - { - $info = array( - 'dep' => $dep, - 'type' => $type, - 'group' => $group - ); - - $dep = array_map('strtolower', $dep); - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); - } - - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } - - if (!isset($data['dependencies'][$channel][$package])) { - $data['dependencies'][$channel][$package] = array(); - } - - $data['dependencies'][$channel][$package][] = $info; - if (isset($data['packages'][$depchannel][$dep['name']])) { - $found = false; - foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { - if ($p['channel'] == $channel && $p['package'] == $package) { - $found = true; - break; - } - } - } else { - if (!isset($data['packages'])) { - $data['packages'] = array(); - } - - if (!isset($data['packages'][$depchannel])) { - $data['packages'][$depchannel] = array(); - } - - if (!isset($data['packages'][$depchannel][$dep['name']])) { - $data['packages'][$depchannel][$dep['name']] = array(); - } - - $found = false; - } - - if (!$found) { - $data['packages'][$depchannel][$dep['name']][] = array( - 'channel' => $channel, - 'package' => $package - ); - } - } -}PEAR-1.9.0/PEAR/Dependency2.php100664 764 764 142517 100664 10760 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Dependency2.php 286494 2009-07-29 06:57:11Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Required for the PEAR_VALIDATE_* constants - */ -require_once 'PEAR/Validate.php'; - -/** - * Dependency check for PEAR packages - * - * This class handles both version 1.0 and 2.0 dependencies - * WARNING: *any* changes to this class must be duplicated in the - * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, - * or unit tests will not actually validate the changes - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Dependency2 -{ - /** - * One of the PEAR_VALIDATE_* states - * @see PEAR_VALIDATE_NORMAL - * @var integer - */ - var $_state; - - /** - * Command-line options to install/upgrade/uninstall commands - * @param array - */ - var $_options; - - /** - * @var OS_Guess - */ - var $_os; - - /** - * @var PEAR_Registry - */ - var $_registry; - - /** - * @var PEAR_Config - */ - var $_config; - - /** - * @var PEAR_DependencyDB - */ - var $_dependencydb; - - /** - * Output of PEAR_Registry::parsedPackageName() - * @var array - */ - var $_currentPackage; - - /** - * @param PEAR_Config - * @param array installation options - * @param array format of PEAR_Registry::parsedPackageName() - * @param int installation state (one of PEAR_VALIDATE_*) - */ - function PEAR_Dependency2(&$config, $installoptions, $package, - $state = PEAR_VALIDATE_INSTALLING) - { - $this->_config = &$config; - if (!class_exists('PEAR_DependencyDB')) { - require_once 'PEAR/DependencyDB.php'; - } - - if (isset($installoptions['packagingroot'])) { - // make sure depdb is in the right location - $config->setInstallRoot($installoptions['packagingroot']); - } - - $this->_registry = &$config->getRegistry(); - $this->_dependencydb = &PEAR_DependencyDB::singleton($config); - if (isset($installoptions['packagingroot'])) { - $config->setInstallRoot(false); - } - - $this->_options = $installoptions; - $this->_state = $state; - if (!class_exists('OS_Guess')) { - require_once 'OS/Guess.php'; - } - - $this->_os = new OS_Guess; - $this->_currentPackage = $package; - } - - function _getExtraString($dep) - { - $extra = ' ('; - if (isset($dep['uri'])) { - return ''; - } - - if (isset($dep['recommended'])) { - $extra .= 'recommended version ' . $dep['recommended']; - } else { - if (isset($dep['min'])) { - $extra .= 'version >= ' . $dep['min']; - } - - if (isset($dep['max'])) { - if ($extra != ' (') { - $extra .= ', '; - } - $extra .= 'version <= ' . $dep['max']; - } - - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if ($extra != ' (') { - $extra .= ', '; - } - - $extra .= 'excluded versions: '; - foreach ($dep['exclude'] as $i => $exclude) { - if ($i) { - $extra .= ', '; - } - $extra .= $exclude; - } - } - } - - $extra .= ')'; - if ($extra == ' ()') { - $extra = ''; - } - - return $extra; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function getPHP_OS() - { - return PHP_OS; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function getsysname() - { - return $this->_os->getSysname(); - } - - /** - * Specify a dependency on an OS. Use arch for detailed os/processor information - * - * There are two generic OS dependencies that will be the most common, unix and windows. - * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix - */ - function validateOsDependency($dep) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - if ($dep['name'] == '*') { - return true; - } - - $not = isset($dep['conflicts']) ? true : false; - switch (strtolower($dep['name'])) { - case 'windows' : - if ($not) { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on Windows"); - } - - return $this->warning("warning: Cannot install %s on Windows"); - } - } else { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on Windows"); - } - - return $this->warning("warning: Can only install %s on Windows"); - } - } - break; - case 'unix' : - $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); - if ($not) { - if (in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on any Unix system"); - } - - return $this->warning( "warning: Cannot install %s on any Unix system"); - } - } else { - if (!in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on a Unix system"); - } - - return $this->warning("warning: Can only install %s on a Unix system"); - } - } - break; - default : - if ($not) { - if (strtolower($dep['name']) == strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . $dep['name'] . - ' operating system'); - } - - return $this->warning('warning: Cannot install %s on ' . - $dep['name'] . ' operating system'); - } - } else { - if (strtolower($dep['name']) != strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } - - return $this->warning('warning: Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } - } - } - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function matchSignature($pattern) - { - return $this->_os->matchSignature($pattern); - } - - /** - * Specify a complex dependency on an OS/processor/kernel version, - * Use OS for simple operating system dependency. - * - * This is the only dependency that accepts an eregable pattern. The pattern - * will be matched against the php_uname() output parsed by OS_Guess - */ - function validateArchDependency($dep) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING) { - return true; - } - - $not = isset($dep['conflicts']) ? true : false; - if (!$this->matchSignature($dep['pattern'])) { - if (!$not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, does not ' . - 'match "' . $dep['pattern'] . '"'); - } - - return $this->warning('warning: %s Architecture dependency failed, does ' . - 'not match "' . $dep['pattern'] . '"'); - } - - return true; - } - - if ($not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, required "' . - $dep['pattern'] . '"'); - } - - return $this->warning('warning: %s Architecture dependency failed, ' . - 'required "' . $dep['pattern'] . '"'); - } - - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function extension_loaded($name) - { - return extension_loaded($name); - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function phpversion($name = null) - { - if ($name !== null) { - return phpversion($name); - } - - return phpversion(); - } - - function validateExtensionDependency($dep, $required = true) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - $loaded = $this->extension_loaded($dep['name']); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } - - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude']) - ) { - if ($loaded) { - if (isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return true; - } - - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return $this->warning('warning: %s requires PHP extension "' . - $dep['name'] . '"' . $extra); - } - - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); - } - - if (!$loaded) { - if (isset($dep['conflicts'])) { - return true; - } - - if (!$required) { - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } - - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } - - $version = (string) $this->phpversion($dep['name']); - if (empty($version)) { - $version = '0'; - } - - $fail = false; - if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { - $fail = true; - } - - if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { - $fail = true; - } - - if ($fail && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (isset($dep['conflicts'])) { - continue; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } - - return $this->warning('warning: %s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - } - } - - if (isset($dep['recommended'])) { - if (version_compare($version, $dep['recommended'], '==')) { - return true; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . - ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'] . - '", but may be compatible, use --force to install'); - } - - return $this->warning('warning: %s dependency: PHP extension ' . - $dep['name'] . ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'].'"'); - } - - return true; - } - - function validatePhpDependency($dep) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - $version = $this->phpversion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } - - if (isset($dep['min'])) { - if (!version_compare($version, $dep['min'], '>=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } - } - - if (isset($dep['max'])) { - if (!version_compare($version, $dep['max'], '<=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } - } - - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP version ' . - $exclude); - } - - return $this->warning( - 'warning: %s is not compatible with PHP version ' . - $exclude); - } - } - } - - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function getPEARVersion() - { - return '1.9.0'; - } - - function validatePearinstallerDependency($dep) - { - $pearversion = $this->getPEARVersion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } - - if (version_compare($pearversion, $dep['min'], '<')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - - if (isset($dep['max'])) { - if (version_compare($pearversion, $dep['max'], '>')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - } - - if (isset($dep['exclude'])) { - if (!isset($dep['exclude'][0])) { - $dep['exclude'] = array($dep['exclude']); - } - - foreach ($dep['exclude'] as $exclude) { - if (version_compare($exclude, $pearversion, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PEAR Installer ' . - 'version ' . $exclude); - } - - return $this->warning('warning: %s is not compatible with PEAR ' . - 'Installer version ' . $exclude); - } - } - } - - return true; - } - - function validateSubpackageDependency($dep, $required, $params) - { - return $this->validatePackageDependency($dep, $required, $params); - } - - /** - * @param array dependency information (2.0 format) - * @param boolean whether this is a required dependency - * @param array a list of downloaded packages to be installed, if any - * @param boolean if true, then deps on pear.php.net that fail will also check - * against pecl.php.net packages to accomodate extensions that have - * moved to pecl.php.net from pear.php.net - */ - function validatePackageDependency($dep, $required, $params, $depv1 = false) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - if (isset($dep['providesextension'])) { - if ($this->extension_loaded($dep['providesextension'])) { - $save = $dep; - $subdep = $dep; - $subdep['name'] = $subdep['providesextension']; - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->validateExtensionDependency($subdep, $required); - PEAR::popErrorHandling(); - if (!PEAR::isError($ret)) { - return true; - } - } - } - - if ($this->_state == PEAR_VALIDATE_INSTALLING) { - return $this->_validatePackageInstall($dep, $required, $depv1); - } - - if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { - return $this->_validatePackageDownload($dep, $required, $params, $depv1); - } - } - - function _validatePackageDownload($dep, $required, $params, $depv1 = false) - { - $dep['package'] = $dep['name']; - if (isset($dep['uri'])) { - $dep['channel'] = '__uri'; - } - - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $found = false; - foreach ($params as $param) { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => $dep['channel']))) { - $found = true; - break; - } - - if ($depv1 && $dep['channel'] == 'pear.php.net') { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => 'pecl.php.net'))) { - $found = true; - break; - } - } - } - - if (!$found && isset($dep['providesextension'])) { - foreach ($params as $param) { - if ($param->isExtension($dep['providesextension'])) { - $found = true; - break; - } - } - } - - if ($found) { - $version = $param->getVersion(); - $installed = false; - $downloaded = true; - } else { - if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - $dep['channel']); - } else { - if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], - 'pear.php.net')) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - 'pear.php.net'); - } else { - $version = 'not installed or downloaded'; - $installed = false; - $downloaded = false; - } - } - } - - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude']) - ) { - if ($installed || $downloaded) { - $installed = $installed ? 'installed' : 'downloaded'; - if (isset($dep['conflicts'])) { - $rest = ''; - if ($version) { - $rest = ", $installed version is " . $version; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); - } - - return true; - } - - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); - } - - if (!$installed && !$downloaded) { - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); - } - - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { - $fail = true; - } - - if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { - $fail = true; - } - - if ($fail && !isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - $dep['package'] = $dep['name']; - $dep = $this->_registry->parsedPackageNameToString($dep, true); - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && - isset($dep['conflicts']) && !isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . - ", $installed version is " . $version); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - if (isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force']) - ) { - return $this->raiseError('%s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } - - return $this->warning('warning: %s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - } - } - - if (isset($dep['recommended'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (version_compare($version, $dep['recommended'], '==')) { - return true; - } - - if (!$found && $installed) { - $param = $this->_registry->getPackage($dep['name'], $dep['channel']); - } - - if ($param) { - $found = false; - foreach ($params as $parent) { - if ($parent->isEqual($this->_currentPackage)) { - $found = true; - break; - } - } - - if ($found) { - if ($param->isCompatible($parent)) { - return true; - } - } else { // this is for validPackage() calls - $parent = $this->_registry->getPackage($this->_currentPackage['package'], - $this->_currentPackage['channel']); - if ($parent !== null && $param->isCompatible($parent)) { - return true; - } - } - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && - !isset($this->_options['loose']) - ) { - return $this->raiseError('%s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended'] . - ', but may be compatible, use --force to install'); - } - - return $this->warning('warning: %s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended']); - } - - return true; - } - - function _validatePackageInstall($dep, $required, $depv1 = false) - { - return $this->_validatePackageDownload($dep, $required, array(), $depv1); - } - - /** - * Verify that uninstalling packages passed in to command line is OK. - * - * @param PEAR_Installer $dl - * @return PEAR_Error|true - */ - function validatePackageUninstall(&$dl) - { - if (PEAR::isError($this->_dependencydb)) { - return $this->_dependencydb; - } - - $params = array(); - // construct an array of "downloaded" packages to fool the package dependency checker - // into using these to validate uninstalls of circular dependencies - $downloaded = &$dl->getUninstallPackages(); - foreach ($downloaded as $i => $pf) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'PEAR/Downloader/Package.php'; - } - $dp = &new PEAR_Downloader_Package($dl); - $dp->setPackageFile($downloaded[$i]); - $params[$i] = &$dp; - } - - // check cache - $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . - strtolower($this->_currentPackage['package']); - if (isset($dl->___uninstall_package_cache)) { - $badpackages = $dl->___uninstall_package_cache; - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } - } - - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); - } - - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } - - return true; - } - - // first, list the immediate parents of each package to be uninstalled - $perpackagelist = array(); - $allparents = array(); - foreach ($params as $i => $param) { - $a = array( - 'channel' => strtolower($param->getChannel()), - 'package' => strtolower($param->getPackage()) - ); - - $deps = $this->_dependencydb->getDependentPackages($a); - if ($deps) { - foreach ($deps as $d) { - $pardeps = $this->_dependencydb->getDependencies($d); - foreach ($pardeps as $dep) { - if (strtolower($dep['dep']['channel']) == $a['channel'] && - strtolower($dep['dep']['name']) == $a['package']) { - if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { - $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); - } - $perpackagelist[$a['channel'] . '/' . $a['package']][] - = array($d['channel'] . '/' . $d['package'], $dep); - if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { - $allparents[$d['channel'] . '/' . $d['package']] = array(); - } - if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { - $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); - } - $allparents[$d['channel'] . '/' . $d['package']] - [$a['channel'] . '/' . $a['package']][] - = array($d, $dep); - } - } - } - } - } - - // next, remove any packages from the parents list that are not installed - $remove = array(); - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { - continue; - } - $remove[$parent] = true; - } - } - - // next remove any packages from the parents list that are not passed in for - // uninstallation - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - foreach ($params as $param) { - if (strtolower($param->getChannel()) == $d[0][0]['channel'] && - strtolower($param->getPackage()) == $d[0][0]['package']) { - // found it - continue 3; - } - } - $remove[$parent] = true; - } - } - - // remove all packages whose dependencies fail - // save which ones failed for error reporting - $badchildren = array(); - do { - $fail = false; - foreach ($remove as $package => $unused) { - if (!isset($allparents[$package])) { - continue; - } - - foreach ($allparents[$package] as $kid => $d1) { - foreach ($d1 as $depinfo) { - if ($depinfo[1]['type'] != 'optional') { - if (isset($badchildren[$kid])) { - continue; - } - $badchildren[$kid] = true; - $remove[$kid] = true; - $fail = true; - continue 2; - } - } - } - if ($fail) { - // start over, we removed some children - continue 2; - } - } - } while ($fail); - - // next, construct the list of packages that can't be uninstalled - $badpackages = array(); - $save = $this->_currentPackage; - foreach ($perpackagelist as $package => $packagedeps) { - foreach ($packagedeps as $parent) { - if (!isset($remove[$parent[0]])) { - continue; - } - - $packagename = $this->_registry->parsePackageName($parent[0]); - $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); - $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); - $packagename['package'] = $pa->getPackage(); - $this->_currentPackage = $packagename; - // parent is not present in uninstall list, make sure we can actually - // uninstall it (parent dep is optional) - $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); - $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); - $parentname['package'] = $pa->getPackage(); - $parent[1]['dep']['package'] = $parentname['package']; - $parent[1]['dep']['channel'] = $parentname['channel']; - if ($parent[1]['type'] == 'optional') { - $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); - if ($test !== true) { - $badpackages[$package]['warnings'][] = $test; - } - } else { - $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); - if ($test !== true) { - $badpackages[$package]['errors'][] = $test; - } - } - } - } - - $this->_currentPackage = $save; - $dl->___uninstall_package_cache = $badpackages; - if (isset($badpackages[$memyselfandI])) { - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } - } - - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); - } - - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } - } - - return true; - } - - function _validatePackageUninstall($dep, $required, $dl) - { - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); - if (!$version) { - return true; - } - - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if (isset($dep['conflicts'])) { - return true; // uninstall OK - these packages conflict (probably installed with --force) - } - - if (!isset($dep['min']) && !isset($dep['max'])) { - if (!$required) { - return $this->warning('"' . $depname . '" can be optionally used by ' . - 'installed package %s' . $extra); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('"' . $depname . '" is required by ' . - 'installed package %s' . $extra); - } - - return $this->warning('warning: "' . $depname . '" is required by ' . - 'installed package %s' . $extra); - } - - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { - $fail = true; - } - - if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { - $fail = true; - } - - // we re-use this variable, preserve the original value - $saverequired = $required; - if (!$required) { - return $this->warning($depname . $extra . ' can be optionally used by installed package' . - ' "%s"'); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError($depname . $extra . ' is required by installed package' . - ' "%s"'); - } - - return $this->raiseError('warning: ' . $depname . $extra . - ' is required by installed package "%s"'); - } - - /** - * validate a downloaded package against installed packages - * - * As of PEAR 1.4.3, this will only validate - * - * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * $pkg package identifier (either - * array('package' => blah, 'channel' => blah) or an array with - * index 'info' referencing an object) - * @param PEAR_Downloader $dl - * @param array $params full list of packages to install - * @return true|PEAR_Error - */ - function validatePackage($pkg, &$dl, $params = array()) - { - if (is_array($pkg) && isset($pkg['info'])) { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); - } else { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); - } - - $fail = false; - if ($deps) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'PEAR/Downloader/Package.php'; - } - - $dp = &new PEAR_Downloader_Package($dl); - if (is_object($pkg)) { - $dp->setPackageFile($pkg); - } else { - $dp->setDownloadURL($pkg); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($deps as $channel => $info) { - foreach ($info as $package => $ds) { - foreach ($params as $packd) { - if (strtolower($packd->getPackage()) == strtolower($package) && - $packd->getChannel() == $channel) { - $dl->log(3, 'skipping installed package check of "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $channel, 'package' => $package), - true) . - '", version "' . $packd->getVersion() . '" will be ' . - 'downloaded and installed'); - continue 2; // jump to next package - } - } - - foreach ($ds as $d) { - $checker = &new PEAR_Dependency2($this->_config, $this->_options, - array('channel' => $channel, 'package' => $package), $this->_state); - $dep = $d['dep']; - $required = $d['type'] == 'required'; - $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); - if (is_array($ret)) { - $dl->log(0, $ret[0]); - } elseif (PEAR::isError($ret)) { - $dl->log(0, $ret->getMessage()); - $fail = true; - } - } - } - } - PEAR::popErrorHandling(); - } - - if ($fail) { - return $this->raiseError( - '%s cannot be installed, conflicts with installed packages'); - } - - return true; - } - - /** - * validate a package.xml 1.0 dependency - */ - function validateDependency1($dep, $params = array()) - { - if (!isset($dep['optional'])) { - $dep['optional'] = 'no'; - } - - list($newdep, $type) = $this->normalizeDep($dep); - if (!$newdep) { - return $this->raiseError("Invalid Dependency"); - } - - if (method_exists($this, "validate{$type}Dependency")) { - return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', - $params, true); - } - } - - /** - * Convert a 1.0 dep into a 2.0 dep - */ - function normalizeDep($dep) - { - $types = array( - 'pkg' => 'Package', - 'ext' => 'Extension', - 'os' => 'Os', - 'php' => 'Php' - ); - - if (!isset($types[$dep['type']])) { - return array(false, false); - } - - $type = $types[$dep['type']]; - - $newdep = array(); - switch ($type) { - case 'Package' : - $newdep['channel'] = 'pear.php.net'; - case 'Extension' : - case 'Os' : - $newdep['name'] = $dep['name']; - break; - } - - $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); - switch ($dep['rel']) { - case 'has' : - return array($newdep, $type); - break; - case 'not' : - $newdep['conflicts'] = true; - break; - case '>=' : - case '>' : - $newdep['min'] = $dep['version']; - if ($dep['rel'] == '>') { - $newdep['exclude'] = $dep['version']; - } - break; - case '<=' : - case '<' : - $newdep['max'] = $dep['version']; - if ($dep['rel'] == '<') { - $newdep['exclude'] = $dep['version']; - } - break; - case 'ne' : - case '!=' : - $newdep['min'] = '0'; - $newdep['max'] = '100000'; - $newdep['exclude'] = $dep['version']; - break; - case '==' : - $newdep['min'] = $dep['version']; - $newdep['max'] = $dep['version']; - break; - } - if ($type == 'Php') { - if (!isset($newdep['min'])) { - $newdep['min'] = '4.4.0'; - } - - if (!isset($newdep['max'])) { - $newdep['max'] = '6.0.0'; - } - } - return array($newdep, $type); - } - - /** - * Converts text comparing operators to them sign equivalents - * - * Example: 'ge' to '>=' - * - * @access public - * @param string Operator - * @return string Sign equivalent - */ - function signOperator($operator) - { - switch($operator) { - case 'lt': return '<'; - case 'le': return '<='; - case 'gt': return '>'; - case 'ge': return '>='; - case 'eq': return '=='; - case 'ne': return '!='; - default: - return $operator; - } - } - - function raiseError($msg) - { - if (isset($this->_options['ignore-errors'])) { - return $this->warning($msg); - } - - return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } - - function warning($msg) - { - return array(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } -}PEAR-1.9.0/PEAR/Downloader.php100664 764 764 201412 100664 10704 - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Downloader.php 287109 2009-08-11 18:50:30Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.0 - */ - -/** - * Needed for constants, extending - */ -require_once 'PEAR/Common.php'; - -define('PEAR_INSTALLER_OK', 1); -define('PEAR_INSTALLER_FAILED', 0); -define('PEAR_INSTALLER_SKIPPED', -1); -define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); - -/** - * Administration class used to download anything from the internet (PEAR Packages, - * static URLs, xml files) - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.0 - */ -class PEAR_Downloader extends PEAR_Common -{ - /** - * @var PEAR_Registry - * @access private - */ - var $_registry; - - /** - * Preferred Installation State (snapshot, devel, alpha, beta, stable) - * @var string|null - * @access private - */ - var $_preferredState; - - /** - * Options from command-line passed to Install. - * - * Recognized options:
    - * - onlyreqdeps : install all required dependencies as well - * - alldeps : install all dependencies, including optional - * - installroot : base relative path to install files in - * - force : force a download even if warnings would prevent it - * - nocompress : download uncompressed tarballs - * @see PEAR_Command_Install - * @access private - * @var array - */ - var $_options; - - /** - * Downloaded Packages after a call to download(). - * - * Format of each entry: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @access private - * @var array - */ - var $_downloadedPackages = array(); - - /** - * Packages slated for download. - * - * This is used to prevent downloading a package more than once should it be a dependency - * for two packages to be installed. - * Format of each entry: - * - *
    -     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
    -     * );
    -     * 
    - * @access private - * @var array - */ - var $_toDownload = array(); - - /** - * Array of every package installed, with names lower-cased. - * - * Format: - * - * array('package1' => 0, 'package2' => 1, ); - * - * @var array - */ - var $_installed = array(); - - /** - * @var array - * @access private - */ - var $_errorStack = array(); - - /** - * @var boolean - * @access private - */ - var $_internalDownload = false; - - /** - * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} - * @var array - * @access private - */ - var $_packageSortTree; - - /** - * Temporary directory, or configuration value where downloads will occur - * @var string - */ - var $_downloadDir; - - /** - * @param PEAR_Frontend_* - * @param array - * @param PEAR_Config - */ - function PEAR_Downloader(&$ui, $options, &$config) - { - parent::PEAR_Common(); - $this->_options = $options; - $this->config = &$config; - $this->_preferredState = $this->config->get('preferred_state'); - $this->ui = &$ui; - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; - } - - if (isset($this->_options['installroot'])) { - $this->config->setInstallRoot($this->_options['installroot']); - } - $this->_registry = &$config->getRegistry(); - - if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { - $this->_installed = $this->_registry->listAllPackages(); - foreach ($this->_installed as $key => $unused) { - if (!count($unused)) { - continue; - } - $strtolower = create_function('$a','return strtolower($a);'); - array_walk($this->_installed[$key], $strtolower); - } - } - } - - /** - * Attempt to discover a channel's remote capabilities from - * its server name - * @param string - * @return boolean - */ - function discover($channel) - { - $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $callback = $this->ui ? array(&$this, '_downloadCallback') : null; - if (!class_exists('System')) { - require_once 'System.php'; - } - - $tmp = System::mktemp(array('-d')); - $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - // Attempt to fallback to https automatically. - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); - $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - return false; - } - } - - list($a, $lastmodified) = $a; - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $b = new PEAR_ChannelFile; - if ($b->fromXmlFile($a)) { - unlink($a); - if ($this->config->get('auto_discover')) { - $this->_registry->addChannel($b, $lastmodified); - $alias = $b->getName(); - if ($b->getName() == $this->_registry->channelName($b->getAlias())) { - $alias = $b->getAlias(); - } - - $this->log(1, 'Auto-discovered channel "' . $channel . - '", alias "' . $alias . '", adding to registry'); - } - - return true; - } - - unlink($a); - return false; - } - - /** - * For simpler unit-testing - * @param PEAR_Downloader - * @return PEAR_Downloader_Package - */ - function &newDownloaderPackage(&$t) - { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'PEAR/Downloader/Package.php'; - } - $a = &new PEAR_Downloader_Package($t); - return $a; - } - - /** - * For simpler unit-testing - * @param PEAR_Config - * @param array - * @param array - * @param int - */ - function &getDependency2Object(&$c, $i, $p, $s) - { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - $z = &new PEAR_Dependency2($c, $i, $p, $s); - return $z; - } - - function &download($params) - { - if (!count($params)) { - $a = array(); - return $a; - } - - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } - - $channelschecked = array(); - // convert all parameters into PEAR_Downloader_Package objects - foreach ($params as $i => $param) { - $params[$i] = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $params[$i]->initialize($param); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - continue; - } - - if (PEAR::isError($err)) { - if (!isset($this->_options['soft']) && $err->getMessage() !== '') { - $this->log(0, $err->getMessage()); - } - - $params[$i] = false; - if (is_object($param)) { - $param = $param->getChannel() . '/' . $param->getPackage(); - } - - if (!isset($this->_options['soft'])) { - $this->log(2, 'Package "' . $param . '" is not valid'); - } - - // Message logged above in a specific verbose mode, passing null to not show up on CLI - $this->pushError(null, PEAR_INSTALLER_SKIPPED); - } else { - do { - if ($params[$i] && $params[$i]->getType() == 'local') { - // bug #7090 skip channel.xml check for local packages - break; - } - - if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && - !isset($this->_options['offline']) - ) { - $channelschecked[$params[$i]->getChannel()] = true; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('System')) { - require_once 'System.php'; - } - - $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); - if (PEAR::isError($curchannel)) { - PEAR::staticPopErrorHandling(); - return $this->raiseError($curchannel); - } - - if (PEAR::isError($dir = $this->getDownloadDir())) { - PEAR::staticPopErrorHandling(); - break; - } - - $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel()); - $url = 'http://' . $mirror . '/channel.xml'; - $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified()); - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - // Attempt fallback to https automatically - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $a = $this->downloadHttp('https://' . $mirror . - '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - break; - } - } - $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . - 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . - '" to update'); - } - } while (false); - - if ($params[$i] && !isset($this->_options['downloadonly'])) { - if (isset($this->_options['packagingroot'])) { - $checkdir = $this->_prependPath( - $this->config->get('php_dir', null, $params[$i]->getChannel()), - $this->_options['packagingroot']); - } else { - $checkdir = $this->config->get('php_dir', - null, $params[$i]->getChannel()); - } - - while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { - $checkdir = dirname($checkdir); - } - - if ($checkdir == '.') { - $checkdir = '/'; - } - - if (!is_writeable($checkdir)) { - return PEAR::raiseError('Cannot install, php_dir for channel "' . - $params[$i]->getChannel() . '" is not writeable by the current user'); - } - } - } - } - - unset($channelschecked); - PEAR_Downloader_Package::removeDuplicates($params); - if (!count($params)) { - $a = array(); - return $a; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { - $reverify = true; - while ($reverify) { - $reverify = false; - foreach ($params as $i => $param) { - //PHP Bug 40768 / PEAR Bug #10944 - //Nested foreaches fail in PHP 5.2.1 - key($params); - $ret = $params[$i]->detectDependencies($params); - if (PEAR::isError($ret)) { - $reverify = true; - $params[$i] = false; - PEAR_Downloader_Package::removeDuplicates($params); - if (!isset($this->_options['soft'])) { - $this->log(0, $ret->getMessage()); - } - continue 2; - } - } - } - } - - if (isset($this->_options['offline'])) { - $this->log(3, 'Skipping dependency download check, --offline specified'); - } - - if (!count($params)) { - $a = array(); - return $a; - } - - while (PEAR_Downloader_Package::mergeDependencies($params)); - PEAR_Downloader_Package::removeDuplicates($params, true); - $errorparams = array(); - if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { - if (count($errorparams)) { - foreach ($errorparams as $param) { - $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); - $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); - } - $a = array(); - return $a; - } - } - - PEAR_Downloader_Package::removeInstalled($params); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($params); - PEAR::popErrorHandling(); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } - - $ret = array(); - $newparams = array(); - if (isset($this->_options['pretend'])) { - return $params; - } - - $somefailed = false; - foreach ($params as $i => $package) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$params[$i]->download(); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (!isset($this->_options['soft'])) { - $this->log(1, $pf->getMessage()); - $this->log(0, 'Error: cannot download "' . - $this->_registry->parsedPackageNameToString($package->getParsedPackage(), - true) . - '"'); - } - $somefailed = true; - continue; - } - - $newparams[] = &$params[$i]; - $ret[] = array( - 'file' => $pf->getArchiveFile(), - 'info' => &$pf, - 'pkg' => $pf->getPackage() - ); - } - - if ($somefailed) { - // remove params that did not download successfully - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($newparams, true); - PEAR::popErrorHandling(); - if (!count($newparams)) { - $this->pushError('Download failed', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } - } - - $this->_downloadedPackages = $ret; - return $newparams; - } - - /** - * @param array all packages to be installed - */ - function analyzeDependencies(&$params, $force = false) - { - $hasfailed = $failed = false; - if (isset($this->_options['downloadonly'])) { - return; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $redo = true; - $reset = false; - while ($redo) { - $redo = false; - foreach ($params as $i => $param) { - $deps = $param->getDeps(); - if (!$deps) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); - - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - continue; - } - - if (!$reset && $param->alreadyValidated() && !$force) { - continue; - } - - if (count($deps)) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); - if ($send === null) { - $send = $param->getDownloadURL(); - } - - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - - $failed = false; - if (isset($deps['required'])) { - foreach ($deps['required'] as $type => $dep) { - // note: Dependency2 will never return a PEAR_Error if ignore-errors - // is specified, so soft is needed to turn off logging - if (!isset($dep[0])) { - if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - - if (isset($deps['optional'])) { - foreach ($deps['optional'] as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - - $groupname = $param->getGroup(); - if (isset($deps['group']) && $groupname) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - $found = false; - foreach ($deps['group'] as $group) { - if ($group['attribs']['name'] == $groupname) { - $found = true; - break; - } - } - - if ($found) { - unset($group['attribs']); - foreach ($group as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - } - } else { - foreach ($deps as $dep) { - if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - $params[$i]->setValidated(); - } - - if ($failed) { - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - } - } - PEAR::staticPopErrorHandling(); - if ($hasfailed && (isset($this->_options['ignore-errors']) || - isset($this->_options['nodeps']))) { - // this is probably not needed, but just in case - if (!isset($this->_options['soft'])) { - $this->log(0, 'WARNING: dependencies failed'); - } - } - } - - /** - * Retrieve the directory that downloads will happen in - * @access private - * @return string - */ - function getDownloadDir() - { - if (isset($this->_downloadDir)) { - return $this->_downloadDir; - } - $downloaddir = $this->config->get('download_dir'); - if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { - if (is_dir($downloaddir) && !is_writable($downloaddir)) { - $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir to avoid this warning'); - } - if (!class_exists('System')) { - require_once 'System.php'; - } - if (PEAR::isError($downloaddir = System::mktemp('-d'))) { - return $downloaddir; - } - $this->log(3, '+ tmp dir created at ' . $downloaddir); - } - if (!is_writable($downloaddir)) { - if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || - !is_writable($downloaddir)) { - return PEAR::raiseError('download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } - } - return $this->_downloadDir = $downloaddir; - } - - function setDownloadDir($dir) - { - if (!@is_writable($dir)) { - if (PEAR::isError(System::mkdir(array('-p', $dir)))) { - return PEAR::raiseError('download directory "' . $dir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } - } - $this->_downloadDir = $dir; - } - - function configSet($key, $value, $layer = 'user', $channel = false) - { - $this->config->set($key, $value, $layer, $channel); - $this->_preferredState = $this->config->get('preferred_state', null, $channel); - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; - } - } - - function setOptions($options) - { - $this->_options = $options; - } - - // }}} - // {{{ setOptions() - function getOptions() - { - return $this->_options; - } - - /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string - */ - function &getPackagefileObject(&$c, $d, $t = false) - { - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - $a = &new PEAR_PackageFile($c, $d, $t); - return $a; - } - - /** - * @param array output of {@link parsePackageName()} - * @access private - */ - function _getPackageDownloadUrl($parr) - { - $curchannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $parr['channel']); - // getDownloadURL returns an array. On error, it only contains information - // on the latest release as array(version, info). On success it contains - // array(version, info, download url string) - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (!$this->_registry->channelExists($parr['channel'])) { - do { - if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { - break; - } - - $this->configSet('default_channel', $curchannel); - return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); - } while (false); - } - - $chan = &$this->_registry->getChannel($parr['channel']); - if (PEAR::isError($chan)) { - return $chan; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); - $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); - // package is installed - use the installed release stability level - if (!isset($parr['state']) && $stability !== null) { - $state = $stability['release']; - } - PEAR::staticPopErrorHandling(); - $base2 = false; - - $preferred_mirror = $this->config->get('preferred_mirror'); - if (!$chan->supportsREST($preferred_mirror) || - ( - !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) - && - !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - ) { - return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); - } - - if ($base2) { - $rest = &$this->config->getREST('1.3', $this->_options); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', $this->_options); - } - - $downloadVersion = false; - if (!isset($parr['version']) && !isset($parr['state']) && $version - && !PEAR::isError($version) - && !isset($this->_options['downloadonly']) - ) { - $downloadVersion = $version; - } - - $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName()); - if (PEAR::isError($url)) { - $this->configSet('default_channel', $curchannel); - return $url; - } - - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); - } - - if (!is_array($url)) { - return $url; - } - - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); - } - - if (!isset($this->_options['force']) && - !isset($this->_options['downloadonly']) && - $version && - !PEAR::isError($version) && - !isset($parr['group']) - ) { - if (version_compare($version, $url['version'], '=')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is the same as the ' . - 'released version ' . $url['version'], -976); - } - - if (version_compare($version, $url['version'], '>')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is newer than detected ' . - 'released version ' . $url['version'], -976); - } - } - - if (isset($url['info']['required']) || $url['compatible']) { - require_once 'PEAR/PackageFile/v2.php'; - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($parr['channel']); - if ($url['compatible']) { - $pf->setRawCompatible($url['compatible']); - } - } else { - require_once 'PEAR/PackageFile/v1.php'; - $pf = new PEAR_PackageFile_v1; - } - - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); - } - - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } - - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; - } - - return $url; - } - - /** - * @param array dependency array - * @access private - */ - function _getDepPackageDownloadUrl($dep, $parr) - { - $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; - $curchannel = $this->config->get('default_channel'); - if (isset($dep['uri'])) { - $xsdversion = '2.0'; - $chan = &$this->_registry->getChannel('__uri'); - if (PEAR::isError($chan)) { - return $chan; - } - - $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); - $this->configSet('default_channel', '__uri'); - } else { - if (isset($dep['channel'])) { - $remotechannel = $dep['channel']; - } else { - $remotechannel = 'pear.php.net'; - } - - if (!$this->_registry->channelExists($remotechannel)) { - do { - if ($this->config->get('auto_discover')) { - if ($this->discover($remotechannel)) { - break; - } - } - return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); - } while (false); - } - - $chan = &$this->_registry->getChannel($remotechannel); - if (PEAR::isError($chan)) { - return $chan; - } - - $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); - $this->configSet('default_channel', $remotechannel); - } - - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (isset($parr['state']) && isset($parr['version'])) { - unset($parr['state']); - } - - if (isset($dep['uri'])) { - $info = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $info->initialize($dep); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - return PEAR::raiseError('Cannot initialize dependency'); - } - - if (PEAR::isError($err)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $err->getMessage()); - } - - if (is_object($info)) { - $param = $info->getChannel() . '/' . $info->getPackage(); - } - return PEAR::raiseError('Package "' . $param . '" is not valid'); - } - return $info; - } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) - && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) - ) { - $rest = &$this->config->getREST('1.0', $this->_options); - $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, - $state, $version, $chan->getName()); - if (PEAR::isError($url)) { - return $url; - } - - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); - } - - if (!is_array($url)) { - return $url; - } - - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); - } - - if (isset($url['info']['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($remotechannel); - } else { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - - } - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); - } - - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } - - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; - } - - return $url; - } - - return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); - } - - /** - * @deprecated in favor of _getPackageDownloadUrl - */ - function getPackageDownloadUrl($package, $version = null, $channel = false) - { - if ($version) { - $package .= "-$version"; - } - if ($this === null || $this->_registry === null) { - $package = "http://pear.php.net/get/$package"; - } else { - $chan = $this->_registry->getChannel($channel); - if (PEAR::isError($chan)) { - return ''; - } - $package = "http://" . $chan->getServer() . "/get/$package"; - } - if (!extension_loaded("zlib")) { - $package .= '?uncompress=yes'; - } - return $package; - } - - /** - * Retrieve a list of downloaded packages after a call to {@link download()}. - * - * Also resets the list of downloaded packages. - * @return array - */ - function getDownloadedPackages() - { - $ret = $this->_downloadedPackages; - $this->_downloadedPackages = array(); - $this->_toDownload = array(); - return $ret; - } - - function _downloadCallback($msg, $params = null) - { - switch ($msg) { - case 'saveas': - $this->log(1, "downloading $params ..."); - break; - case 'done': - $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); - break; - case 'bytesread': - static $bytes; - if (empty($bytes)) { - $bytes = 0; - } - if (!($bytes % 10240)) { - $this->log(1, '.', false); - } - $bytes += $params; - break; - case 'start': - if($params[1] == -1) { - $length = "Unknown size"; - } else { - $length = number_format($params[1], 0, '', ',')." bytes"; - } - $this->log(1, "Starting to download {$params[0]} ($length)"); - break; - } - if (method_exists($this->ui, '_downloadCallback')) - $this->ui->_downloadCallback($msg, $params); - } - - function _prependPath($path, $prepend) - { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; - } - } - return $path; - } - - /** - * @param string - * @param integer - */ - function pushError($errmsg, $code = -1) - { - array_push($this->_errorStack, array($errmsg, $code)); - } - - function getErrorMsgs() - { - $msgs = array(); - $errs = $this->_errorStack; - foreach ($errs as $err) { - $msgs[] = $err[0]; - } - $this->_errorStack = array(); - return $msgs; - } - - /** - * for BC - * - * @deprecated - */ - function sortPkgDeps(&$packages, $uninstall = false) - { - $uninstall ? - $this->sortPackagesForUninstall($packages) : - $this->sortPackagesForInstall($packages); - } - - /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * This uses the topological sort method from graph theory, and the - * Structures_Graph package to properly sort dependencies for installation. - * @param array an array of downloaded PEAR_Downloader_Packages - * @return array array of array(packagefilename, package.xml contents) - */ - function sortPackagesForInstall(&$packages) - { - require_once 'Structures/Graph.php'; - require_once 'Structures/Graph/Node.php'; - require_once 'Structures/Graph/Manipulator/TopologicalSorter.php'; - $depgraph = new Structures_Graph(true); - $nodes = array(); - $reg = &$this->config->getRegistry(); - foreach ($packages as $i => $package) { - $pname = $reg->parsedPackageNameToString( - array( - 'channel' => $package->getChannel(), - 'package' => strtolower($package->getPackage()), - )); - $nodes[$pname] = new Structures_Graph_Node; - $nodes[$pname]->setData($packages[$i]); - $depgraph->addNode($nodes[$pname]); - } - - $deplinks = array(); - foreach ($nodes as $package => $node) { - $pf = &$node->getData(); - $pdeps = $pf->getDeps(true); - if (!$pdeps) { - continue; - } - - if ($pf->getPackagexmlVersion() == '1.0') { - foreach ($pdeps as $dep) { - if ($dep['type'] != 'pkg' || - (isset($dep['optional']) && $dep['optional'] == 'yes')) { - continue; - } - - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pear.php.net', - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } - - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } - - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pecl.php.net', - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } - - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } - } - } else { - // the only ordering we care about is: - // 1) subpackages must be installed before packages that depend on them - // 2) required deps must be installed before packages that depend on them - if (isset($pdeps['required']['subpackage'])) { - $t = $pdeps['required']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } - - foreach ($pdeps['group'] as $group) { - if (isset($group['subpackage'])) { - $t = $group['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } - } - - if (isset($pdeps['optional']['subpackage'])) { - $t = $pdeps['optional']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['required']['package'])) { - $t = $pdeps['required']['package']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } - - foreach ($pdeps['group'] as $group) { - if (isset($group['package'])) { - $t = $group['package']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } - } - } - } - - $this->_detectDepCycle($deplinks); - foreach ($deplinks as $dependent => $parents) { - foreach ($parents as $parent => $unused) { - $nodes[$dependent]->connectTo($nodes[$parent]); - } - } - - $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); - $ret = array(); - for ($i = 0, $count = count($installOrder); $i < $count; $i++) { - foreach ($installOrder[$i] as $index => $sortedpackage) { - $data = &$installOrder[$i][$index]->getData(); - $ret[] = &$nodes[$reg->parsedPackageNameToString( - array( - 'channel' => $data->getChannel(), - 'package' => strtolower($data->getPackage()), - ))]->getData(); - } - } - - $packages = $ret; - return; - } - - /** - * Detect recursive links between dependencies and break the cycles - * - * @param array - * @access private - */ - function _detectDepCycle(&$deplinks) - { - do { - $keepgoing = false; - foreach ($deplinks as $dep => $parents) { - foreach ($parents as $parent => $unused) { - // reset the parent cycle detector - $this->_testCycle(null, null, null); - if ($this->_testCycle($dep, $deplinks, $parent)) { - $keepgoing = true; - unset($deplinks[$dep][$parent]); - if (count($deplinks[$dep]) == 0) { - unset($deplinks[$dep]); - } - - continue 3; - } - } - } - } while ($keepgoing); - } - - function _testCycle($test, $deplinks, $dep) - { - static $visited = array(); - if ($test === null) { - $visited = array(); - return; - } - - // this happens when a parent has a dep cycle on another dependency - // but the child is not part of the cycle - if (isset($visited[$dep])) { - return false; - } - - $visited[$dep] = 1; - if ($test == $dep) { - return true; - } - - if (isset($deplinks[$dep])) { - if (in_array($test, array_keys($deplinks[$dep]), true)) { - return true; - } - - foreach ($deplinks[$dep] as $parent => $unused) { - if ($this->_testCycle($test, $deplinks, $parent)) { - return true; - } - } - } - - return false; - } - - /** - * Set up the dependency for installation parsing - * - * @param array $t dependency information - * @param PEAR_Registry $reg - * @param array $deplinks list of dependency links already established - * @param array $nodes all existing package nodes - * @param string $package parent package name - * @access private - */ - function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) - { - foreach ($t as $dep) { - $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => $depchannel, - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } - $deplinks[$dname][$package] = 1; - } - } - } - - function _dependsOn($a, $b) - { - return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); - } - - function _checkDepTree($channel, $package, $b, $checked = array()) - { - $checked[$channel][$package] = true; - if (!isset($this->_depTree[$channel][$package])) { - return false; - } - - if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] - [strtolower($b->getPackage())])) { - return true; - } - - foreach ($this->_depTree[$channel][$package] as $ch => $packages) { - foreach ($packages as $pa => $true) { - if ($this->_checkDepTree($ch, $pa, $b, $checked)) { - return true; - } - } - } - - return false; - } - - function _sortInstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return 1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return -1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependsOn($a, $b)) { - return 1; - } - if ($this->_dependsOn($b, $a)) { - return -1; - } - return 0; - } - - /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP/SSL connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir directory to save file in - * @param mixed $callback function/method to call for status - * updates - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @param false|string $channel Channel to use for retrieving authentication - * @return string|array Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. - * - * @access public - */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, - $accept = false, $channel = false) - { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - if ($callback) { - call_user_func($callback, 'setup', array(&$ui)); - } - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); - } - - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); - } - - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; - - if (isset($this)) { - $config = &$this->config; - } else { - $config = &PEAR_Config::singleton(); - } - - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($config->get('http_proxy') && - $proxy = parse_url($config->get('http_proxy'))) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - - if ($callback) { - call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); - } - } - - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; - } - - $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; - - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, - $errno, $errstr)); - } - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); - } - - if ($lastmodified === false || $lastmodified) { - $request = "GET $url HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $url HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } - } else { - $network_host = $host; - if (isset($info['scheme']) && $info['scheme'] == 'https') { - $network_host = 'ssl://' . $host; - } - - $fp = @fsockopen($network_host, $port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($host, $port, - $errno, $errstr)); - } - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); - } - - if ($lastmodified === false || $lastmodified) { - $request = "GET $path HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $path HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } - } - - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; - } - - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; - } - } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); - } - - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; - - if (isset($this)) { // only pass in authentication for non-static calls - $username = $config->get('username', null, $channel); - $password = $config->get('password', null, $channel); - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; - } - } - - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; - } - - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; - } - - $request .= "Connection: close\r\n"; - $request .= "\r\n"; - fwrite($fp, $request); - $headers = array(); - $reply = 0; - while (trim($line = fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; - } - - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); - } - } - } - - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); - } - - if ($wasredirect > 4) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); - } - - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], - $ui, $save_dir, $callback, $lastmodified, $accept); - } - - if (isset($headers['content-disposition']) && - preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { - $save_as = basename($matches[1]); - } else { - $save_as = basename($url); - } - - if ($callback) { - $tmp = call_user_func($callback, 'saveas', $save_as); - if ($tmp) { - $save_as = $tmp; - } - } - - $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; - if (!$wp = @fopen($dest_file, 'wb')) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); - } - return PEAR::raiseError("could not open $dest_file for writing"); - } - - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - - $bytes = 0; - if ($callback) { - call_user_func($callback, 'start', array(basename($dest_file), $length)); - } - - while ($data = fread($fp, 1024)) { - $bytes += strlen($data); - if ($callback) { - call_user_func($callback, 'bytesread', $bytes); - } - if (!@fwrite($wp, $data)) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); - } - return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); - } - } - - fclose($fp); - fclose($wp); - if ($callback) { - call_user_func($callback, 'done', $bytes); - } - - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); - } - - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; - } else { - $lastmodified = $headers['last-modified']; - } - } - return array($dest_file, $lastmodified, $headers); - } - return $dest_file; - } -} -// }}}PEAR-1.9.0/PEAR/ErrorStack.php100664 764 764 102251 100664 10666 - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ - -/** - * Singleton storage - * - * Format: - *
    - * array(
    - *  'package1' => PEAR_ErrorStack object,
    - *  'package2' => PEAR_ErrorStack object,
    - *  ...
    - * )
    - * 
    - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] - */ -$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); - -/** - * Global error callback (default) - * - * This is only used if set to non-false. * is the default callback for - * all packages, whereas specific packages may set a default callback - * for all instances, regardless of whether they are a singleton or not. - * - * To exclude non-singletons, only set the local callback for the singleton - * @see PEAR_ErrorStack::setDefaultCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( - '*' => false, -); - -/** - * Global Log object (default) - * - * This is only used if set to non-false. Use to set a default log object for - * all stacks, regardless of instantiation order or location - * @see PEAR_ErrorStack::setDefaultLogger() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; - -/** - * Global Overriding Callback - * - * This callback will override any error callbacks that specific loggers have set. - * Use with EXTREME caution - * @see PEAR_ErrorStack::staticPushCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - -/**#@+ - * One of four possible return values from the error Callback - * @see PEAR_ErrorStack::_errorCallback() - */ -/** - * If this is returned, then the error will be both pushed onto the stack - * and logged. - */ -define('PEAR_ERRORSTACK_PUSHANDLOG', 1); -/** - * If this is returned, then the error will only be pushed onto the stack, - * and not logged. - */ -define('PEAR_ERRORSTACK_PUSH', 2); -/** - * If this is returned, then the error will only be logged, but not pushed - * onto the error stack. - */ -define('PEAR_ERRORSTACK_LOG', 3); -/** - * If this is returned, then the error is completely ignored. - */ -define('PEAR_ERRORSTACK_IGNORE', 4); -/** - * If this is returned, then the error is logged and die() is called. - */ -define('PEAR_ERRORSTACK_DIE', 5); -/**#@-*/ - -/** - * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in - * the singleton method. - */ -define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); - -/** - * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} - * that has no __toString() method - */ -define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); -/** - * Error Stack Implementation - * - * Usage: - * - * // global error stack - * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); - * // local error stack - * $local_stack = new PEAR_ErrorStack('MyPackage'); - * - * @author Greg Beaver - * @version 1.9.0 - * @package PEAR_ErrorStack - * @category Debugging - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ -class PEAR_ErrorStack { - /** - * Errors are stored in the order that they are pushed on the stack. - * @since 0.4alpha Errors are no longer organized by error level. - * This renders pop() nearly unusable, and levels could be more easily - * handled in a callback anyway - * @var array - * @access private - */ - var $_errors = array(); - - /** - * Storage of errors by level. - * - * Allows easy retrieval and deletion of only errors from a particular level - * @since PEAR 1.4.0dev - * @var array - * @access private - */ - var $_errorsByLevel = array(); - - /** - * Package name this error stack represents - * @var string - * @access protected - */ - var $_package; - - /** - * Determines whether a PEAR_Error is thrown upon every error addition - * @var boolean - * @access private - */ - var $_compat = false; - - /** - * If set to a valid callback, this will be used to generate the error - * message from the error code, otherwise the message passed in will be - * used - * @var false|string|array - * @access private - */ - var $_msgCallback = false; - - /** - * If set to a valid callback, this will be used to generate the error - * context for an error. For PHP-related errors, this will be a file - * and line number as retrieved from debug_backtrace(), but can be - * customized for other purposes. The error might actually be in a separate - * configuration file, or in a database query. - * @var false|string|array - * @access protected - */ - var $_contextCallback = false; - - /** - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one an PEAR_ERRORSTACK_* constant - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @var false|string|array - * @access protected - */ - var $_errorCallback = array(); - - /** - * PEAR::Log object for logging errors - * @var false|Log - * @access protected - */ - var $_logger = false; - - /** - * Error messages - designed to be overridden - * @var array - * @abstract - */ - var $_errorMsgs = array(); - - /** - * Set up a new error stack - * - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - */ - function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false) - { - $this->_package = $package; - $this->setMessageCallback($msgCallback); - $this->setContextCallback($contextCallback); - $this->_compat = $throwPEAR_Error; - } - - /** - * Return a single error stack for this package. - * - * Note that all parameters are ignored if the stack for package $package - * has already been instantiated - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - * @param string $stackClass class to instantiate - * @static - * @return PEAR_ErrorStack - */ - function &singleton($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') - { - if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - if (!class_exists($stackClass)) { - if (function_exists('debug_backtrace')) { - $trace = debug_backtrace(); - } - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, - 'exception', array('stackclass' => $stackClass), - 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', - false, $trace); - } - $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = - new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); - - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - - /** - * Internal error handler for PEAR_ErrorStack class - * - * Dies if the error is an exception (and would have died anyway) - * @access private - */ - function _handleError($err) - { - if ($err['level'] == 'exception') { - $message = $err['message']; - if (isset($_SERVER['REQUEST_URI'])) { - echo '
    '; - } else { - echo "\n"; - } - var_dump($err['context']); - die($message); - } - } - - /** - * Set up a PEAR::Log object for all error stacks that don't have one - * @param Log $log - * @static - */ - function setDefaultLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } elseif (is_callable($log)) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } - } - - /** - * Set up a PEAR::Log object for this error stack - * @param Log $log - */ - function setLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $this->_logger = &$log; - } elseif (is_callable($log)) { - $this->_logger = &$log; - } - } - - /** - * Set an error code => error message mapping callback - * - * This method sets the callback that can be used to generate error - * messages for any instance - * @param array|string Callback function/method - */ - function setMessageCallback($msgCallback) - { - if (!$msgCallback) { - $this->_msgCallback = array(&$this, 'getErrorMessage'); - } else { - if (is_callable($msgCallback)) { - $this->_msgCallback = $msgCallback; - } - } - } - - /** - * Get an error code => error message mapping callback - * - * This method returns the current callback that can be used to generate error - * messages - * @return array|string|false Callback function/method or false if none - */ - function getMessageCallback() - { - return $this->_msgCallback; - } - - /** - * Sets a default callback to be used by all error stacks - * - * This method sets the callback that can be used to generate error - * messages for a singleton - * @param array|string Callback function/method - * @param string Package name, or false for all packages - * @static - */ - function setDefaultCallback($callback = false, $package = false) - { - if (!is_callable($callback)) { - $callback = false; - } - $package = $package ? $package : '*'; - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; - } - - /** - * Set a callback that generates context information (location of error) for an error stack - * - * This method sets the callback that can be used to generate context - * information for an error. Passing in NULL will disable context generation - * and remove the expensive call to debug_backtrace() - * @param array|string|null Callback function/method - */ - function setContextCallback($contextCallback) - { - if ($contextCallback === null) { - return $this->_contextCallback = false; - } - if (!$contextCallback) { - $this->_contextCallback = array(&$this, 'getFileLine'); - } else { - if (is_callable($contextCallback)) { - $this->_contextCallback = $contextCallback; - } - } - } - - /** - * Set an error Callback - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one of the ERRORSTACK_* constants. - * - * This functionality can be used to emulate PEAR's pushErrorHandling, and - * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of - * the error stack or logging - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see popCallback() - * @param string|array $cb - */ - function pushCallback($cb) - { - array_push($this->_errorCallback, $cb); - } - - /** - * Remove a callback from the error callback stack - * @see pushCallback() - * @return array|string|false - */ - function popCallback() - { - if (!count($this->_errorCallback)) { - return false; - } - return array_pop($this->_errorCallback); - } - - /** - * Set a temporary overriding error callback for every package error stack - * - * Use this to temporarily disable all existing callbacks (can be used - * to emulate the @ operator, for instance) - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see staticPopCallback(), pushCallback() - * @param string|array $cb - * @static - */ - function staticPushCallback($cb) - { - array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); - } - - /** - * Remove a temporary overriding error callback - * @see staticPushCallback() - * @return array|string|false - * @static - */ - function staticPopCallback() - { - $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); - if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { - $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - } - return $ret; - } - - /** - * Add an error to the stack - * - * If the message generator exists, it is called with 2 parameters. - * - the current Error Stack object - * - an array that is in the same format as an error. Available indices - * are 'code', 'package', 'time', 'params', 'level', and 'context' - * - * Next, if the error should contain context information, this is - * handled by the context grabbing method. - * Finally, the error is pushed onto the proper error stack - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. If a PEAR_Error is returned, the userinfo - * property is set to the following array: - * - * - * array( - * 'code' => $code, - * 'params' => $params, - * 'package' => $this->_package, - * 'level' => $level, - * 'time' => time(), - * 'context' => $context, - * 'message' => $msg, - * //['repackage' => $err] repackaged error array/Exception class - * ); - * - * - * Normally, the previous array is returned. - */ - function push($code, $level = 'error', $params = array(), $msg = false, - $repackage = false, $backtrace = false) - { - $context = false; - // grab error context - if ($this->_contextCallback) { - if (!$backtrace) { - $backtrace = debug_backtrace(); - } - $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); - } - - // save error - $time = explode(' ', microtime()); - $time = $time[1] + $time[0]; - $err = array( - 'code' => $code, - 'params' => $params, - 'package' => $this->_package, - 'level' => $level, - 'time' => $time, - 'context' => $context, - 'message' => $msg, - ); - - if ($repackage) { - $err['repackage'] = $repackage; - } - - // set up the error message, if necessary - if ($this->_msgCallback) { - $msg = call_user_func_array($this->_msgCallback, - array(&$this, $err)); - $err['message'] = $msg; - } - $push = $log = true; - $die = false; - // try the overriding callback first - $callback = $this->staticPopCallback(); - if ($callback) { - $this->staticPushCallback($callback); - } - if (!is_callable($callback)) { - // try the local callback next - $callback = $this->popCallback(); - if (is_callable($callback)) { - $this->pushCallback($callback); - } else { - // try the default callback - $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; - } - } - if (is_callable($callback)) { - switch(call_user_func($callback, $err)){ - case PEAR_ERRORSTACK_IGNORE: - return $err; - break; - case PEAR_ERRORSTACK_PUSH: - $log = false; - break; - case PEAR_ERRORSTACK_LOG: - $push = false; - break; - case PEAR_ERRORSTACK_DIE: - $die = true; - break; - // anything else returned has the same effect as pushandlog - } - } - if ($push) { - array_unshift($this->_errors, $err); - if (!isset($this->_errorsByLevel[$err['level']])) { - $this->_errorsByLevel[$err['level']] = array(); - } - $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; - } - if ($log) { - if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { - $this->_log($err); - } - } - if ($die) { - die(); - } - if ($this->_compat && $push) { - return $this->raiseError($msg, $code, null, null, $err); - } - return $err; - } - - /** - * Static version of {@link push()} - * - * @param string $package Package name this error belongs to - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. see docs for {@link push()} - * @static - */ - function staticPush($package, $code, $level = 'error', $params = array(), - $msg = false, $repackage = false, $backtrace = false) - { - $s = &PEAR_ErrorStack::singleton($package); - if ($s->_contextCallback) { - if (!$backtrace) { - if (function_exists('debug_backtrace')) { - $backtrace = debug_backtrace(); - } - } - } - return $s->push($code, $level, $params, $msg, $repackage, $backtrace); - } - - /** - * Log an error using PEAR::Log - * @param array $err Error array - * @param array $levels Error level => Log constant map - * @access protected - */ - function _log($err) - { - if ($this->_logger) { - $logger = &$this->_logger; - } else { - $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; - } - if (is_a($logger, 'Log')) { - $levels = array( - 'exception' => PEAR_LOG_CRIT, - 'alert' => PEAR_LOG_ALERT, - 'critical' => PEAR_LOG_CRIT, - 'error' => PEAR_LOG_ERR, - 'warning' => PEAR_LOG_WARNING, - 'notice' => PEAR_LOG_NOTICE, - 'info' => PEAR_LOG_INFO, - 'debug' => PEAR_LOG_DEBUG); - if (isset($levels[$err['level']])) { - $level = $levels[$err['level']]; - } else { - $level = PEAR_LOG_INFO; - } - $logger->log($err['message'], $level, $err); - } else { // support non-standard logs - call_user_func($logger, $err); - } - } - - - /** - * Pop an error off of the error stack - * - * @return false|array - * @since 0.4alpha it is no longer possible to specify a specific error - * level to return - the last error pushed will be returned, instead - */ - function pop() - { - $err = @array_shift($this->_errors); - if (!is_null($err)) { - @array_pop($this->_errorsByLevel[$err['level']]); - if (!count($this->_errorsByLevel[$err['level']])) { - unset($this->_errorsByLevel[$err['level']]); - } - } - return $err; - } - - /** - * Pop an error off of the error stack, static method - * - * @param string package name - * @return boolean - * @since PEAR1.5.0a1 - */ - function staticPop($package) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); - } - } - - /** - * Determine whether there are any errors on the stack - * @param string|array Level name. Use to determine if any errors - * of level (string), or levels (array) have been pushed - * @return boolean - */ - function hasErrors($level = false) - { - if ($level) { - return isset($this->_errorsByLevel[$level]); - } - return count($this->_errors); - } - - /** - * Retrieve all errors since last purge - * - * @param boolean set in order to empty the error stack - * @param string level name, to return only errors of a particular severity - * @return array - */ - function getErrors($purge = false, $level = false) - { - if (!$purge) { - if ($level) { - if (!isset($this->_errorsByLevel[$level])) { - return array(); - } else { - return $this->_errorsByLevel[$level]; - } - } else { - return $this->_errors; - } - } - if ($level) { - $ret = $this->_errorsByLevel[$level]; - foreach ($this->_errorsByLevel[$level] as $i => $unused) { - // entries are references to the $_errors array - $this->_errorsByLevel[$level][$i] = false; - } - // array_filter removes all entries === false - $this->_errors = array_filter($this->_errors); - unset($this->_errorsByLevel[$level]); - return $ret; - } - $ret = $this->_errors; - $this->_errors = array(); - $this->_errorsByLevel = array(); - return $ret; - } - - /** - * Determine whether there are any errors on a single error stack, or on any error stack - * - * The optional parameter can be used to test the existence of any errors without the need of - * singleton instantiation - * @param string|false Package name to check for errors - * @param string Level name to check for a particular severity - * @return boolean - * @static - */ - function staticHasErrors($package = false, $level = false) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - if ($obj->hasErrors($level)) { - return true; - } - } - return false; - } - - /** - * Get a list of all errors since last purge, organized by package - * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be - * @param boolean $purge Set to purge the error stack of existing errors - * @param string $level Set to a level name in order to retrieve only errors of a particular level - * @param boolean $merge Set to return a flat array, not organized by package - * @param array $sortfunc Function used to sort a merged array - default - * sorts by time, and should be good for most cases - * @static - * @return array - */ - function staticGetErrors($purge = false, $level = false, $merge = false, - $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) - { - $ret = array(); - if (!is_callable($sortfunc)) { - $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); - if ($test) { - if ($merge) { - $ret = array_merge($ret, $test); - } else { - $ret[$package] = $test; - } - } - } - if ($merge) { - usort($ret, $sortfunc); - } - return $ret; - } - - /** - * Error sorting function, sorts by time - * @access private - */ - function _sortErrors($a, $b) - { - if ($a['time'] == $b['time']) { - return 0; - } - if ($a['time'] < $b['time']) { - return 1; - } - return -1; - } - - /** - * Standard file/line number/function/class context callback - * - * This function uses a backtrace generated from {@link debug_backtrace()} - * and so will not work at all in PHP < 4.3.0. The frame should - * reference the frame that contains the source of the error. - * @return array|false either array('file' => file, 'line' => line, - * 'function' => function name, 'class' => class name) or - * if this doesn't work, then false - * @param unused - * @param integer backtrace frame. - * @param array Results of debug_backtrace() - * @static - */ - function getFileLine($code, $params, $backtrace = null) - { - if ($backtrace === null) { - return false; - } - $frame = 0; - $functionframe = 1; - if (!isset($backtrace[1])) { - $functionframe = 0; - } else { - while (isset($backtrace[$functionframe]['function']) && - $backtrace[$functionframe]['function'] == 'eval' && - isset($backtrace[$functionframe + 1])) { - $functionframe++; - } - } - if (isset($backtrace[$frame])) { - if (!isset($backtrace[$frame]['file'])) { - $frame++; - } - $funcbacktrace = $backtrace[$functionframe]; - $filebacktrace = $backtrace[$frame]; - $ret = array('file' => $filebacktrace['file'], - 'line' => $filebacktrace['line']); - // rearrange for eval'd code or create function errors - if (strpos($filebacktrace['file'], '(') && - preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], - $matches)) { - $ret['file'] = $matches[1]; - $ret['line'] = $matches[2] + 0; - } - if (isset($funcbacktrace['function']) && isset($backtrace[1])) { - if ($funcbacktrace['function'] != 'eval') { - if ($funcbacktrace['function'] == '__lambda_func') { - $ret['function'] = 'create_function() code'; - } else { - $ret['function'] = $funcbacktrace['function']; - } - } - } - if (isset($funcbacktrace['class']) && isset($backtrace[1])) { - $ret['class'] = $funcbacktrace['class']; - } - return $ret; - } - return false; - } - - /** - * Standard error message generation callback - * - * This method may also be called by a custom error message generator - * to fill in template values from the params array, simply - * set the third parameter to the error message template string to use - * - * The special variable %__msg% is reserved: use it only to specify - * where a message passed in by the user should be placed in the template, - * like so: - * - * Error message: %msg% - internal error - * - * If the message passed like so: - * - * - * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); - * - * - * The returned error message will be "Error message: server error 500 - - * internal error" - * @param PEAR_ErrorStack - * @param array - * @param string|false Pre-generated error message template - * @static - * @return string - */ - function getErrorMessage(&$stack, $err, $template = false) - { - if ($template) { - $mainmsg = $template; - } else { - $mainmsg = $stack->getErrorMessageTemplate($err['code']); - } - $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); - if (is_array($err['params']) && count($err['params'])) { - foreach ($err['params'] as $name => $val) { - if (is_array($val)) { - // @ is needed in case $val is a multi-dimensional array - $val = @implode(', ', $val); - } - if (is_object($val)) { - if (method_exists($val, '__toString')) { - $val = $val->__toString(); - } else { - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, - 'warning', array('obj' => get_class($val)), - 'object %obj% passed into getErrorMessage, but has no __toString() method'); - $val = 'Object'; - } - } - $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); - } - } - return $mainmsg; - } - - /** - * Standard Error Message Template generator from code - * @return string - */ - function getErrorMessageTemplate($code) - { - if (!isset($this->_errorMsgs[$code])) { - return '%__msg%'; - } - return $this->_errorMsgs[$code]; - } - - /** - * Set the Error Message Template array - * - * The array format must be: - *
    -     * array(error code => 'message template',...)
    -     * 
    - * - * Error message parameters passed into {@link push()} will be used as input - * for the error message. If the template is 'message %foo% was %bar%', and the - * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will - * be 'message one was six' - * @return string - */ - function setErrorMessageTemplate($template) - { - $this->_errorMsgs = $template; - } - - - /** - * emulate PEAR::raiseError() - * - * @return PEAR_Error - */ - function raiseError() - { - require_once 'PEAR.php'; - $args = func_get_args(); - return call_user_func_array(array('PEAR', 'raiseError'), $args); - } -} -$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); -$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); -?> -PEAR-1.9.0/PEAR/Exception.php100664 764 764 33031 100664 10524 - * @author Hans Lellelid - * @author Bertrand Mansion - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Exception.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.3 - */ - - -/** - * Base PEAR_Exception Class - * - * 1) Features: - * - * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) - * - Definable triggers, shot when exceptions occur - * - Pretty and informative error messages - * - Added more context info available (like class, method or cause) - * - cause can be a PEAR_Exception or an array of mixed - * PEAR_Exceptions/PEAR_ErrorStack warnings - * - callbacks for specific exception classes and their children - * - * 2) Ideas: - * - * - Maybe a way to define a 'template' for the output - * - * 3) Inherited properties from PHP Exception Class: - * - * protected $message - * protected $code - * protected $line - * protected $file - * private $trace - * - * 4) Inherited methods from PHP Exception Class: - * - * __clone - * __construct - * getMessage - * getCode - * getFile - * getLine - * getTraceSafe - * getTraceSafeAsString - * __toString - * - * 5) Usage example - * - * - * require_once 'PEAR/Exception.php'; - * - * class Test { - * function foo() { - * throw new PEAR_Exception('Error Message', ERROR_CODE); - * } - * } - * - * function myLogger($pear_exception) { - * echo $pear_exception->getMessage(); - * } - * // each time a exception is thrown the 'myLogger' will be called - * // (its use is completely optional) - * PEAR_Exception::addObserver('myLogger'); - * $test = new Test; - * try { - * $test->foo(); - * } catch (PEAR_Exception $e) { - * print $e; - * } - * - * - * @category pear - * @package PEAR - * @author Tomas V.V.Cox - * @author Hans Lellelid - * @author Bertrand Mansion - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.3 - * - */ -class PEAR_Exception extends Exception -{ - const OBSERVER_PRINT = -2; - const OBSERVER_TRIGGER = -4; - const OBSERVER_DIE = -8; - protected $cause; - private static $_observers = array(); - private static $_uniqueid = 0; - private $_trace; - - /** - * Supported signatures: - * - PEAR_Exception(string $message); - * - PEAR_Exception(string $message, int $code); - * - PEAR_Exception(string $message, Exception $cause); - * - PEAR_Exception(string $message, Exception $cause, int $code); - * - PEAR_Exception(string $message, PEAR_Error $cause); - * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); - * - PEAR_Exception(string $message, array $causes); - * - PEAR_Exception(string $message, array $causes, int $code); - * @param string exception message - * @param int|Exception|PEAR_Error|array|null exception cause - * @param int|null exception code or null - */ - public function __construct($message, $p2 = null, $p3 = null) - { - if (is_int($p2)) { - $code = $p2; - $this->cause = null; - } elseif (is_object($p2) || is_array($p2)) { - // using is_object allows both Exception and PEAR_Error - if (is_object($p2) && !($p2 instanceof Exception)) { - if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { - throw new PEAR_Exception('exception cause must be Exception, ' . - 'array, or PEAR_Error'); - } - } - $code = $p3; - if (is_array($p2) && isset($p2['message'])) { - // fix potential problem of passing in a single warning - $p2 = array($p2); - } - $this->cause = $p2; - } else { - $code = null; - $this->cause = null; - } - parent::__construct($message, $code); - $this->signal(); - } - - /** - * @param mixed $callback - A valid php callback, see php func is_callable() - * - A PEAR_Exception::OBSERVER_* constant - * - An array(const PEAR_Exception::OBSERVER_*, - * mixed $options) - * @param string $label The name of the observer. Use this if you want - * to remove it later with removeObserver() - */ - public static function addObserver($callback, $label = 'default') - { - self::$_observers[$label] = $callback; - } - - public static function removeObserver($label = 'default') - { - unset(self::$_observers[$label]); - } - - /** - * @return int unique identifier for an observer - */ - public static function getUniqueId() - { - return self::$_uniqueid++; - } - - private function signal() - { - foreach (self::$_observers as $func) { - if (is_callable($func)) { - call_user_func($func, $this); - continue; - } - settype($func, 'array'); - switch ($func[0]) { - case self::OBSERVER_PRINT : - $f = (isset($func[1])) ? $func[1] : '%s'; - printf($f, $this->getMessage()); - break; - case self::OBSERVER_TRIGGER : - $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; - trigger_error($this->getMessage(), $f); - break; - case self::OBSERVER_DIE : - $f = (isset($func[1])) ? $func[1] : '%s'; - die(printf($f, $this->getMessage())); - break; - default: - trigger_error('invalid observer type', E_USER_WARNING); - } - } - } - - /** - * Return specific error information that can be used for more detailed - * error messages or translation. - * - * This method may be overridden in child exception classes in order - * to add functionality not present in PEAR_Exception and is a placeholder - * to define API - * - * The returned array must be an associative array of parameter => value like so: - *
    -     * array('name' => $name, 'context' => array(...))
    -     * 
    - * @return array - */ - public function getErrorData() - { - return array(); - } - - /** - * Returns the exception that caused this exception to be thrown - * @access public - * @return Exception|array The context of the exception - */ - public function getCause() - { - return $this->cause; - } - - /** - * Function must be public to call on caused exceptions - * @param array - */ - public function getCauseMessage(&$causes) - { - $trace = $this->getTraceSafe(); - $cause = array('class' => get_class($this), - 'message' => $this->message, - 'file' => 'unknown', - 'line' => 'unknown'); - if (isset($trace[0])) { - if (isset($trace[0]['file'])) { - $cause['file'] = $trace[0]['file']; - $cause['line'] = $trace[0]['line']; - } - } - $causes[] = $cause; - if ($this->cause instanceof PEAR_Exception) { - $this->cause->getCauseMessage($causes); - } elseif ($this->cause instanceof Exception) { - $causes[] = array('class' => get_class($this->cause), - 'message' => $this->cause->getMessage(), - 'file' => $this->cause->getFile(), - 'line' => $this->cause->getLine()); - } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { - $causes[] = array('class' => get_class($this->cause), - 'message' => $this->cause->getMessage(), - 'file' => 'unknown', - 'line' => 'unknown'); - } elseif (is_array($this->cause)) { - foreach ($this->cause as $cause) { - if ($cause instanceof PEAR_Exception) { - $cause->getCauseMessage($causes); - } elseif ($cause instanceof Exception) { - $causes[] = array('class' => get_class($cause), - 'message' => $cause->getMessage(), - 'file' => $cause->getFile(), - 'line' => $cause->getLine()); - } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { - $causes[] = array('class' => get_class($cause), - 'message' => $cause->getMessage(), - 'file' => 'unknown', - 'line' => 'unknown'); - } elseif (is_array($cause) && isset($cause['message'])) { - // PEAR_ErrorStack warning - $causes[] = array( - 'class' => $cause['package'], - 'message' => $cause['message'], - 'file' => isset($cause['context']['file']) ? - $cause['context']['file'] : - 'unknown', - 'line' => isset($cause['context']['line']) ? - $cause['context']['line'] : - 'unknown', - ); - } - } - } - } - - public function getTraceSafe() - { - if (!isset($this->_trace)) { - $this->_trace = $this->getTrace(); - if (empty($this->_trace)) { - $backtrace = debug_backtrace(); - $this->_trace = array($backtrace[count($backtrace)-1]); - } - } - return $this->_trace; - } - - public function getErrorClass() - { - $trace = $this->getTraceSafe(); - return $trace[0]['class']; - } - - public function getErrorMethod() - { - $trace = $this->getTraceSafe(); - return $trace[0]['function']; - } - - public function __toString() - { - if (isset($_SERVER['REQUEST_URI'])) { - return $this->toHtml(); - } - return $this->toText(); - } - - public function toHtml() - { - $trace = $this->getTraceSafe(); - $causes = array(); - $this->getCauseMessage($causes); - $html = '' . "\n"; - foreach ($causes as $i => $cause) { - $html .= '\n"; - } - $html .= '' . "\n" - . '' - . '' - . '' . "\n"; - - foreach ($trace as $k => $v) { - $html .= '' - . '' - . '' . "\n"; - } - $html .= '' - . '' - . '' . "\n" - . '
    ' - . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' - . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' - . 'on line ' . $cause['line'] . '' - . "
    Exception trace
    #FunctionLocation
    ' . $k . ''; - if (!empty($v['class'])) { - $html .= $v['class'] . $v['type']; - } - $html .= $v['function']; - $args = array(); - if (!empty($v['args'])) { - foreach ($v['args'] as $arg) { - if (is_null($arg)) $args[] = 'null'; - elseif (is_array($arg)) $args[] = 'Array'; - elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; - elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; - elseif (is_int($arg) || is_double($arg)) $args[] = $arg; - else { - $arg = (string)$arg; - $str = htmlspecialchars(substr($arg, 0, 16)); - if (strlen($arg) > 16) $str .= '…'; - $args[] = "'" . $str . "'"; - } - } - } - $html .= '(' . implode(', ',$args) . ')' - . '' . (isset($v['file']) ? $v['file'] : 'unknown') - . ':' . (isset($v['line']) ? $v['line'] : 'unknown') - . '
    ' . ($k+1) . '{main} 
    '; - return $html; - } - - public function toText() - { - $causes = array(); - $this->getCauseMessage($causes); - $causeMsg = ''; - foreach ($causes as $i => $cause) { - $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' - . $cause['message'] . ' in ' . $cause['file'] - . ' on line ' . $cause['line'] . "\n"; - } - return $causeMsg . $this->getTraceAsString(); - } -} - -?>PEAR-1.9.0/PEAR/FixPHP5PEARWarnings.php100664 764 764 231 100664 12066 PEAR-1.9.0/PEAR/Frontend.php100664 764 764 15077 100664 10357 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Frontend.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Include error handling - */ -//require_once 'PEAR.php'; - -/** - * Which user interface class is being used. - * @var string class name - */ -$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; - -/** - * Instance of $_PEAR_Command_uiclass. - * @var object - */ -$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; - -/** - * Singleton-based frontend for PEAR user input/output - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Frontend extends PEAR -{ - /** - * Retrieve the frontend object - * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk - * @static - */ - function &singleton($type = null) - { - if ($type === null) { - if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { - $a = false; - return $a; - } - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - $a = PEAR_Frontend::setFrontendClass($type); - return $a; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to conform to the PEAR naming standard of - * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) - * @param string $uiclass full class name - * @return PEAR_Frontend - * @static - */ - function &setFrontendClass($uiclass) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!class_exists($uiclass)) { - $file = str_replace('_', '/', $uiclass) . '.php'; - if (PEAR_Frontend::isIncludeable($file)) { - include_once $file; - } - } - - if (class_exists($uiclass)) { - $obj = &new $uiclass; - // quick test to see if this class implements a few of the most - // important frontend methods - if (is_a($obj, 'PEAR_Frontend')) { - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; - return $obj; - } - - $err = PEAR::raiseError("not a frontend class: $uiclass"); - return $err; - } - - $err = PEAR::raiseError("no such class: $uiclass"); - return $err; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to be a descendant of PEAR_Frontend - * @param PEAR_Frontend - * @return PEAR_Frontend - * @static - */ - function &setFrontendObject($uiobject) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!is_a($uiobject, 'PEAR_Frontend')) { - $err = PEAR::raiseError('not a valid frontend class: (' . - get_class($uiobject) . ')'); - return $err; - } - - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); - return $uiobject; - } - - /** - * @param string $path relative or absolute include path - * @return boolean - * @static - */ - function isIncludeable($path) - { - if (file_exists($path) && is_readable($path)) { - return true; - } - - $fp = @fopen($path, 'r', true); - if ($fp) { - fclose($fp); - return true; - } - - return false; - } - - /** - * @param PEAR_Config - */ - function setConfig(&$config) - { - } - - /** - * This can be overridden to allow session-based temporary file management - * - * By default, all files are deleted at the end of a session. The web installer - * needs to be able to sustain a list over many sessions in order to support - * user interaction with install scripts - */ - function addTempFile($file) - { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; - } - - /** - * Log an action - * - * @param string $msg the message to log - * @param boolean $append_crlf - * @return boolean true - * @abstract - */ - function log($msg, $append_crlf = true) - { - } - - /** - * Run a post-installation script - * - * @param array $scripts array of post-install scripts - * @abstract - */ - function runPostinstallScripts(&$scripts) - { - } - - /** - * Display human-friendly output formatted depending on the - * $command parameter. - * - * This should be able to handle basic output data with no command - * @param mixed $data data structure containing the information to display - * @param string $command command from which this method was called - * @abstract - */ - function outputData($data, $command = '_default') - { - } - - /** - * Display a modal form dialog and return the given input - * - * A frontend that requires multiple requests to retrieve and process - * data must take these needs into account, and implement the request - * handling code. - * @param string $command command from which this method was called - * @param array $prompts associative array. keys are the input field names - * and values are the description - * @param array $types array of input field types (text, password, - * etc.) keys have to be the same like in $prompts - * @param array $defaults array of default values. again keys have - * to be the same like in $prompts. Do not depend - * on a default value being set. - * @return array input sent by the user - * @abstract - */ - function userDialog($command, $prompts, $types = array(), $defaults = array()) - { - } -}PEAR-1.9.0/PEAR/Installer.php100664 764 764 210603 100664 10545 - * @author Tomas V.V. Cox - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Installer.php 287446 2009-08-18 11:45:05Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Used for installation groups in package.xml 2.0 and platform exceptions - */ -require_once 'OS/Guess.php'; -require_once 'PEAR/Downloader.php'; - -define('PEAR_INSTALLER_NOBINARY', -240); -/** - * Administration class used to install PEAR packages and maintain the - * installed package database. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Installer extends PEAR_Downloader -{ - // {{{ properties - - /** name of the package directory, for example Foo-1.0 - * @var string - */ - var $pkgdir; - - /** directory where PHP code files go - * @var string - */ - var $phpdir; - - /** directory where PHP extension files go - * @var string - */ - var $extdir; - - /** directory where documentation goes - * @var string - */ - var $docdir; - - /** installation root directory (ala PHP's INSTALL_ROOT or - * automake's DESTDIR - * @var string - */ - var $installroot = ''; - - /** debug level - * @var int - */ - var $debug = 1; - - /** temporary directory - * @var string - */ - var $tmpdir; - - /** - * PEAR_Registry object used by the installer - * @var PEAR_Registry - */ - var $registry; - - /** - * array of PEAR_Downloader_Packages - * @var array - */ - var $_downloadedPackages; - - /** List of file transactions queued for an install/upgrade/uninstall. - * - * Format: - * array( - * 0 => array("rename => array("from-file", "to-file")), - * 1 => array("delete" => array("file-to-delete")), - * ... - * ) - * - * @var array - */ - var $file_operations = array(); - - // }}} - - // {{{ constructor - - /** - * PEAR_Installer constructor. - * - * @param object $ui user interface object (instance of PEAR_Frontend_*) - * - * @access public - */ - function PEAR_Installer(&$ui) - { - parent::PEAR_Common(); - $this->setFrontendObject($ui); - $this->debug = $this->config->get('verbose'); - } - - function setOptions($options) - { - $this->_options = $options; - } - - function setConfig(&$config) - { - $this->config = &$config; - $this->_registry = &$config->getRegistry(); - } - - // }}} - - function _removeBackups($files) - { - foreach ($files as $path) { - $this->addFileOperation('removebackup', array($path)); - } - } - - // {{{ _deletePackageFiles() - - /** - * Delete a package's installed files, does not remove empty directories. - * - * @param string package name - * @param string channel name - * @param bool if true, then files are backed up first - * @return bool TRUE on success, or a PEAR error on failure - * @access protected - */ - function _deletePackageFiles($package, $channel = false, $backup = false) - { - if (!$channel) { - $channel = 'pear.php.net'; - } - - if (!strlen($package)) { - return $this->raiseError("No package to uninstall given"); - } - - if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { - // to avoid race conditions, include all possible needed files - require_once 'PEAR/Task/Common.php'; - require_once 'PEAR/Task/Replace.php'; - require_once 'PEAR/Task/Unixeol.php'; - require_once 'PEAR/Task/Windowseol.php'; - require_once 'PEAR/PackageFile/v1.php'; - require_once 'PEAR/PackageFile/v2.php'; - require_once 'PEAR/PackageFile/Generator/v1.php'; - require_once 'PEAR/PackageFile/Generator/v2.php'; - } - - $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); - if ($filelist == null) { - return $this->raiseError("$channel/$package not installed"); - } - - $ret = array(); - foreach ($filelist as $file => $props) { - if (empty($props['installed_as'])) { - continue; - } - - $path = $props['installed_as']; - if ($backup) { - $this->addFileOperation('backup', array($path)); - $ret[] = $path; - } - - $this->addFileOperation('delete', array($path)); - } - - if ($backup) { - return $ret; - } - - return true; - } - - // }}} - // {{{ _installFile() - - /** - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private - */ - function _installFile($file, $atts, $tmp_path, $options) - { - // {{{ return if this file is meant for another platform - static $os; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } - - if (isset($atts['platform'])) { - if (empty($os)) { - $os = new OS_Guess(); - } - - if (strlen($atts['platform']) && $atts['platform']{0} == '!') { - $negate = true; - $platform = substr($atts['platform'], 1); - } else { - $negate = false; - $platform = $atts['platform']; - } - - if ((bool) $os->matchSignature($platform) === $negate) { - $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); - return PEAR_INSTALLER_SKIPPED; - } - } - // }}} - - $channel = $this->pkginfo->getChannel(); - // {{{ assemble the destination paths - switch ($atts['role']) { - case 'src': - case 'extsrc': - $this->source_files++; - return; - case 'doc': - case 'data': - case 'test': - $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . - DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); - unset($atts['baseinstalldir']); - break; - case 'ext': - case 'php': - $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); - break; - case 'script': - $dest_dir = $this->config->get('bin_dir', null, $channel); - break; - default: - return $this->raiseError("Invalid role `$atts[role]' for file $file"); - } - - $save_destdir = $dest_dir; - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - - if (dirname($file) != '.' && empty($atts['install-as'])) { - $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); - } - - if (empty($atts['install-as'])) { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); - } else { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; - } - $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; - - // Clean up the DIRECTORY_SEPARATOR mess - $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; - list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), - array(DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR), - array($dest_file, $orig_file)); - $final_dest_file = $installed_as = $dest_file; - if (isset($this->_options['packagingroot'])) { - $installedas_dest_dir = dirname($final_dest_file); - $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']); - } else { - $installedas_dest_dir = dirname($final_dest_file); - $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - } - - $dest_dir = dirname($final_dest_file); - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { - return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); - } - // }}} - - if (empty($this->_options['register-only']) && - (!file_exists($dest_dir) || !is_dir($dest_dir))) { - if (!$this->mkDirHier($dest_dir)) { - return $this->raiseError("failed to mkdir $dest_dir", - PEAR_INSTALLER_FAILED); - } - $this->log(3, "+ mkdir $dest_dir"); - } - - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (empty($atts['replacements'])) { - if (!file_exists($orig_file)) { - return $this->raiseError("file $orig_file does not exist", - PEAR_INSTALLER_FAILED); - } - - if (!@copy($orig_file, $dest_file)) { - return $this->raiseError("failed to write $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ cp $orig_file $dest_file"); - if (isset($atts['md5sum'])) { - $md5sum = md5_file($dest_file); - } - } else { - // {{{ file with replacements - if (!file_exists($orig_file)) { - return $this->raiseError("file does not exist", - PEAR_INSTALLER_FAILED); - } - - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } - - if (isset($atts['md5sum'])) { - $md5sum = md5($contents); - } - - $subst_from = $subst_to = array(); - foreach ($atts['replacements'] as $a) { - $to = ''; - if ($a['type'] == 'php-const') { - if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { - eval("\$to = $a[to];"); - } else { - if (!isset($options['soft'])) { - $this->log(0, "invalid php-const replacement: $a[to]"); - } - continue; - } - } elseif ($a['type'] == 'pear-config') { - if ($a['to'] == 'master_server') { - $chan = $this->_registry->getChannel($channel); - if (!PEAR::isError($chan)) { - $to = $chan->getServer(); - } else { - $to = $this->config->get($a['to'], null, $channel); - } - } else { - $to = $this->config->get($a['to'], null, $channel); - } - if (is_null($to)) { - if (!isset($options['soft'])) { - $this->log(0, "invalid pear-config replacement: $a[to]"); - } - continue; - } - } elseif ($a['type'] == 'package-info') { - if ($t = $this->pkginfo->packageInfo($a['to'])) { - $to = $t; - } else { - if (!isset($options['soft'])) { - $this->log(0, "invalid package-info replacement: $a[to]"); - } - continue; - } - } - if (!is_null($to)) { - $subst_from[] = $a['from']; - $subst_to[] = $to; - } - } - - $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); - if (sizeof($subst_from)) { - $contents = str_replace($subst_from, $subst_to, $contents); - } - - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - if (@fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - fclose($wp); - // }}} - } - - // {{{ check the md5 - if (isset($md5sum)) { - if (strtolower($md5sum) === strtolower($atts['md5sum'])) { - $this->log(2, "md5sum ok: $final_dest_file"); - } else { - if (empty($options['force'])) { - // delete the file - if (file_exists($dest_file)) { - unlink($dest_file); - } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError("bad md5sum for file $final_dest_file", - PEAR_INSTALLER_FAILED); - } - - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } else { - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } - } - } - // }}} - // {{{ set file permissions - if (!OS_WINDOWS) { - if ($atts['role'] == 'script') { - $mode = 0777 & ~(int)octdec($this->config->get('umask')); - $this->log(3, "+ chmod +x $dest_file"); - } else { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - } - - if ($atts['role'] != 'src') { - $this->addFileOperation("chmod", array($mode, $dest_file)); - if (!@chmod($dest_file, $mode)) { - if (!isset($options['soft'])) { - $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); - } - } - } - } - // }}} - - if ($atts['role'] == 'src') { - rename($dest_file, $final_dest_file); - $this->log(2, "renamed source file $dest_file to $final_dest_file"); - } else { - $this->addFileOperation("rename", array($dest_file, $final_dest_file, - $atts['role'] == 'ext')); - } - } - - // Store the full path where the file was installed for easy unistall - if ($atts['role'] != 'script') { - $loc = $this->config->get($atts['role'] . '_dir'); - } else { - $loc = $this->config->get('bin_dir'); - } - - if ($atts['role'] != 'src') { - $this->addFileOperation("installed_as", array($file, $installed_as, - $loc, - dirname(substr($installedas_dest_file, strlen($loc))))); - } - - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; - } - - // }}} - // {{{ _installFile2() - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private - */ - function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) - { - $atts = $real_atts; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } - - $channel = $pkg->getChannel(); - // {{{ assemble the destination paths - if (!in_array($atts['attribs']['role'], - PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { - return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . - "' for file $file"); - } - - $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); - $err = $role->setup($this, $pkg, $atts['attribs'], $file); - if (PEAR::isError($err)) { - return $err; - } - - if (!$role->isInstallable()) { - return; - } - - $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); - if (PEAR::isError($info)) { - return $info; - } - - list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; - if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { - return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); - } - - $final_dest_file = $installed_as = $dest_file; - if (isset($this->_options['packagingroot'])) { - $final_dest_file = $this->_prependPath($final_dest_file, - $this->_options['packagingroot']); - } - - $dest_dir = dirname($final_dest_file); - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - // }}} - - if (empty($this->_options['register-only'])) { - if (!file_exists($dest_dir) || !is_dir($dest_dir)) { - if (!$this->mkDirHier($dest_dir)) { - return $this->raiseError("failed to mkdir $dest_dir", - PEAR_INSTALLER_FAILED); - } - $this->log(3, "+ mkdir $dest_dir"); - } - } - - $attribs = $atts['attribs']; - unset($atts['attribs']); - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (!count($atts)) { // no tasks - if (!file_exists($orig_file)) { - return $this->raiseError("file $orig_file does not exist", - PEAR_INSTALLER_FAILED); - } - - if (!@copy($orig_file, $dest_file)) { - return $this->raiseError("failed to write $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ cp $orig_file $dest_file"); - if (isset($attribs['md5sum'])) { - $md5sum = md5_file($dest_file); - } - } else { // file with tasks - if (!file_exists($orig_file)) { - return $this->raiseError("file $orig_file does not exist", - PEAR_INSTALLER_FAILED); - } - - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } - - if (isset($attribs['md5sum'])) { - $md5sum = md5($contents); - } - - foreach ($atts as $tag => $raw) { - $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag); - $task = "PEAR_Task_$tag"; - $task = &new $task($this->config, $this, PEAR_TASK_INSTALL); - if (!$task->isScript()) { // scripts are only handled after installation - $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); - $res = $task->startSession($pkg, $contents, $final_dest_file); - if ($res === false) { - continue; // skip this file - } - - if (PEAR::isError($res)) { - return $res; - } - - $contents = $res; // save changes - } - - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - if (fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - fclose($wp); - } - } - - // {{{ check the md5 - if (isset($md5sum)) { - // Make sure the original md5 sum matches with expected - if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { - $this->log(2, "md5sum ok: $final_dest_file"); - - if (isset($contents)) { - // set md5 sum based on $content in case any tasks were run. - $real_atts['attribs']['md5sum'] = md5($contents); - } - } else { - if (empty($options['force'])) { - // delete the file - if (file_exists($dest_file)) { - unlink($dest_file); - } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError("bad md5sum for file $final_dest_file", - PEAR_INSTALLER_FAILED); - } - - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } else { - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } - } - } else { - $real_atts['attribs']['md5sum'] = md5_file($dest_file); - } - - // }}} - // {{{ set file permissions - if (!OS_WINDOWS) { - if ($role->isExecutable()) { - $mode = 0777 & ~(int)octdec($this->config->get('umask')); - $this->log(3, "+ chmod +x $dest_file"); - } else { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - } - - if ($attribs['role'] != 'src') { - $this->addFileOperation("chmod", array($mode, $dest_file)); - if (!@chmod($dest_file, $mode)) { - if (!isset($options['soft'])) { - $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); - } - } - } - } - // }}} - - if ($attribs['role'] == 'src') { - rename($dest_file, $final_dest_file); - $this->log(2, "renamed source file $dest_file to $final_dest_file"); - } else { - $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); - } - } - - // Store the full path where the file was installed for easy uninstall - if ($attribs['role'] != 'src') { - $loc = $this->config->get($role->getLocationConfig(), null, $channel); - $this->addFileOperation('installed_as', array($file, $installed_as, - $loc, - dirname(substr($installed_as, strlen($loc))))); - } - - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; - } - - // }}} - // {{{ addFileOperation() - - /** - * Add a file operation to the current file transaction. - * - * @see startFileTransaction() - * @param string $type This can be one of: - * - rename: rename a file ($data has 3 values) - * - backup: backup an existing file ($data has 1 value) - * - removebackup: clean up backups created during install ($data has 1 value) - * - chmod: change permissions on a file ($data has 2 values) - * - delete: delete a file ($data has 1 value) - * - rmdir: delete a directory if empty ($data has 1 value) - * - installed_as: mark a file as installed ($data has 4 values). - * @param array $data For all file operations, this array must contain the - * full path to the file or directory that is being operated on. For - * the rename command, the first parameter must be the file to rename, - * the second its new name, the third whether this is a PHP extension. - * - * The installed_as operation contains 4 elements in this order: - * 1. Filename as listed in the filelist element from package.xml - * 2. Full path to the installed file - * 3. Full path from the php_dir configuration variable used in this - * installation - * 4. Relative path from the php_dir that this file is installed in - */ - function addFileOperation($type, $data) - { - if (!is_array($data)) { - return $this->raiseError('Internal Error: $data in addFileOperation' - . ' must be an array, was ' . gettype($data)); - } - - if ($type == 'chmod') { - $octmode = decoct($data[0]); - $this->log(3, "adding to transaction: $type $octmode $data[1]"); - } else { - $this->log(3, "adding to transaction: $type " . implode(" ", $data)); - } - $this->file_operations[] = array($type, $data); - } - - // }}} - // {{{ startFileTransaction() - - function startFileTransaction($rollback_in_case = false) - { - if (count($this->file_operations) && $rollback_in_case) { - $this->rollbackFileTransaction(); - } - $this->file_operations = array(); - } - - // }}} - // {{{ commitFileTransaction() - - function commitFileTransaction() - { - $n = count($this->file_operations); - $this->log(2, "about to commit $n file operations"); - // {{{ first, check permissions and such manually - $errors = array(); - foreach ($this->file_operations as $tr) { - list($type, $data) = $tr; - switch ($type) { - case 'rename': - if (!file_exists($data[0])) { - $errors[] = "cannot rename file $data[0], doesn't exist"; - } - - // check that dest dir. is writable - if (!is_writable(dirname($data[1]))) { - $errors[] = "permission denied ($type): $data[1]"; - } - break; - case 'chmod': - // check that file is writable - if (!is_writable($data[1])) { - $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); - } - break; - case 'delete': - if (!file_exists($data[0])) { - $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); - } - // check that directory is writable - if (file_exists($data[0])) { - if (!is_writable(dirname($data[0]))) { - $errors[] = "permission denied ($type): $data[0]"; - } else { - // make sure the file to be deleted can be opened for writing - $fp = false; - if (!is_dir($data[0]) && - (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { - $errors[] = "permission denied ($type): $data[0]"; - } elseif ($fp) { - fclose($fp); - } - } - } - break; - } - - } - // }}} - $m = count($errors); - if ($m > 0) { - foreach ($errors as $error) { - if (!isset($this->_options['soft'])) { - $this->log(1, $error); - } - } - - if (!isset($this->_options['ignore-errors'])) { - return false; - } - } - - $this->_dirtree = array(); - // {{{ really commit the transaction - foreach ($this->file_operations as $i => $tr) { - if (!$tr) { - // support removal of non-existing backups - continue; - } - - list($type, $data) = $tr; - switch ($type) { - case 'backup': - if (!file_exists($data[0])) { - $this->file_operations[$i] = false; - break; - } - - if (!@copy($data[0], $data[0] . '.bak')) { - $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . - '.bak ' . $php_errormsg); - return false; - } - $this->log(3, "+ backup $data[0] to $data[0].bak"); - break; - case 'removebackup': - if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { - unlink($data[0] . '.bak'); - $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); - } - break; - case 'rename': - $test = file_exists($data[1]) ? @unlink($data[1]) : null; - if (!$test && file_exists($data[1])) { - if ($data[2]) { - $extra = ', this extension must be installed manually. Rename to "' . - basename($data[1]) . '"'; - } else { - $extra = ''; - } - - if (!isset($this->_options['soft'])) { - $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . - $data[0] . $extra); - } - - if (!isset($this->_options['ignore-errors'])) { - return false; - } - } - - // permissions issues with rename - copy() is far superior - $perms = @fileperms($data[0]); - if (!@copy($data[0], $data[1])) { - $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . - ' ' . $php_errormsg); - return false; - } - - // copy over permissions, otherwise they are lost - @chmod($data[1], $perms); - @unlink($data[0]); - $this->log(3, "+ mv $data[0] $data[1]"); - break; - case 'chmod': - if (!@chmod($data[1], $data[0])) { - $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . - decoct($data[0]) . ' ' . $php_errormsg); - return false; - } - - $octmode = decoct($data[0]); - $this->log(3, "+ chmod $octmode $data[1]"); - break; - case 'delete': - if (file_exists($data[0])) { - if (!@unlink($data[0])) { - $this->log(1, 'Could not delete ' . $data[0] . ' ' . - $php_errormsg); - return false; - } - $this->log(3, "+ rm $data[0]"); - } - break; - case 'rmdir': - if (file_exists($data[0])) { - do { - $testme = opendir($data[0]); - while (false !== ($entry = readdir($testme))) { - if ($entry == '.' || $entry == '..') { - continue; - } - closedir($testme); - break 2; // this directory is not empty and can't be - // deleted - } - - closedir($testme); - if (!@rmdir($data[0])) { - $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . - $php_errormsg); - return false; - } - $this->log(3, "+ rmdir $data[0]"); - } while (false); - } - break; - case 'installed_as': - $this->pkginfo->setInstalledAs($data[0], $data[1]); - if (!isset($this->_dirtree[dirname($data[1])])) { - $this->_dirtree[dirname($data[1])] = true; - $this->pkginfo->setDirtree(dirname($data[1])); - - while(!empty($data[3]) && dirname($data[3]) != $data[3] && - $data[3] != '/' && $data[3] != '\\') { - $this->pkginfo->setDirtree($pp = - $this->_prependPath($data[3], $data[2])); - $this->_dirtree[$pp] = true; - $data[3] = dirname($data[3]); - } - } - break; - } - } - // }}} - $this->log(2, "successfully committed $n file operations"); - $this->file_operations = array(); - return true; - } - - // }}} - // {{{ rollbackFileTransaction() - - function rollbackFileTransaction() - { - $n = count($this->file_operations); - $this->log(2, "rolling back $n file operations"); - foreach ($this->file_operations as $tr) { - list($type, $data) = $tr; - switch ($type) { - case 'backup': - if (file_exists($data[0] . '.bak')) { - if (file_exists($data[0] && is_writable($data[0]))) { - unlink($data[0]); - } - @copy($data[0] . '.bak', $data[0]); - $this->log(3, "+ restore $data[0] from $data[0].bak"); - } - break; - case 'removebackup': - if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { - unlink($data[0] . '.bak'); - $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); - } - break; - case 'rename': - @unlink($data[0]); - $this->log(3, "+ rm $data[0]"); - break; - case 'mkdir': - @rmdir($data[0]); - $this->log(3, "+ rmdir $data[0]"); - break; - case 'chmod': - break; - case 'delete': - break; - case 'installed_as': - $this->pkginfo->setInstalledAs($data[0], false); - break; - } - } - $this->pkginfo->resetDirtree(); - $this->file_operations = array(); - } - - // }}} - // {{{ mkDirHier($dir) - - function mkDirHier($dir) - { - $this->addFileOperation('mkdir', array($dir)); - return parent::mkDirHier($dir); - } - - // }}} - // {{{ download() - - /** - * Download any files and their dependencies, if necessary - * - * @param array a mixed list of package names, local files, or package.xml - * @param PEAR_Config - * @param array options from the command line - * @param array this is the array that will be populated with packages to - * install. Format of each entry: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @param array this will be populated with any error messages - * @param false private recursion variable - * @param false private recursion variable - * @param false private recursion variable - * @deprecated in favor of PEAR_Downloader - */ - function download($packages, $options, &$config, &$installpackages, - &$errors, $installed = false, $willinstall = false, $state = false) - { - // trickiness: initialize here - parent::PEAR_Downloader($this->ui, $options, $config); - $ret = parent::download($packages); - $errors = $this->getErrorMsgs(); - $installpackages = $this->getDownloadedPackages(); - trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . - "in favor of PEAR_Downloader class", E_USER_WARNING); - return $ret; - } - - // }}} - // {{{ _parsePackageXml() - - function _parsePackageXml(&$descfile, &$tmpdir) - { - if (substr($descfile, -4) == '.xml') { - $tmpdir = false; - } else { - // {{{ Decompress pack in tmp dir ------------------------------------- - - // To allow relative package file names - $descfile = realpath($descfile); - - if (PEAR::isError($tmpdir = System::mktemp('-d'))) { - return $tmpdir; - } - $this->log(3, '+ tmp dir created at ' . $tmpdir); - // }}} - } - - // Parse xml file ----------------------------------------------- - $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($p)) { - if (is_array($p->getUserInfo())) { - foreach ($p->getUserInfo() as $err) { - $loglevel = $err['level'] == 'error' ? 0 : 1; - if (!isset($this->_options['soft'])) { - $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); - } - } - } - return $this->raiseError('Installation failed: invalid package file'); - } - - $descfile = $p->getPackageFile(); - return $p; - } - - // }}} - /** - * Set the list of PEAR_Downloader_Package objects to allow more sane - * dependency validation - * @param array - */ - function setDownloadedPackages(&$pkgs) - { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($pkgs); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - return $err; - } - $this->_downloadedPackages = &$pkgs; - } - - /** - * Set the list of PEAR_Downloader_Package objects to allow more sane - * dependency validation - * @param array - */ - function setUninstallPackages(&$pkgs) - { - $this->_downloadedPackages = &$pkgs; - } - - function getInstallPackages() - { - return $this->_downloadedPackages; - } - - // {{{ install() - - /** - * Installs the files within the package file specified. - * - * @param string|PEAR_Downloader_Package $pkgfile path to the package file, - * or a pre-initialized packagefile object - * @param array $options - * recognized options: - * - installroot : optional prefix directory for installation - * - force : force installation - * - register-only : update registry but don't install files - * - upgrade : upgrade existing install - * - soft : fail silently - * - nodeps : ignore dependency conflicts/missing dependencies - * - alldeps : install all dependencies - * - onlyreqdeps : install only required dependencies - * - * @return array|PEAR_Error package info if successful - */ - function install($pkgfile, $options = array()) - { - $this->_options = $options; - $this->_registry = &$this->config->getRegistry(); - if (is_object($pkgfile)) { - $dlpkg = &$pkgfile; - $pkg = $pkgfile->getPackageFile(); - $pkgfile = $pkg->getArchiveFile(); - $descfile = $pkg->getPackageFile(); - $tmpdir = dirname($descfile); - } else { - $descfile = $pkgfile; - $tmpdir = ''; - $pkg = $this->_parsePackageXml($descfile, $tmpdir); - if (PEAR::isError($pkg)) { - return $pkg; - } - } - - if (realpath($descfile) != realpath($pkgfile)) { - $tar = new Archive_Tar($pkgfile); - if (!$tar->extract($tmpdir)) { - return $this->raiseError("unable to unpack $pkgfile"); - } - } - - $pkgname = $pkg->getName(); - $channel = $pkg->getChannel(); - if (isset($this->_options['packagingroot'])) { - $regdir = $this->_prependPath( - $this->config->get('php_dir', null, 'pear.php.net'), - $this->_options['packagingroot']); - - $packrootphp_dir = $this->_prependPath( - $this->config->get('php_dir', null, $channel), - $this->_options['packagingroot']); - } - - if (isset($options['installroot'])) { - $this->config->setInstallRoot($options['installroot']); - $this->_registry = &$this->config->getRegistry(); - $installregistry = &$this->_registry; - $this->installroot = ''; // all done automagically now - $php_dir = $this->config->get('php_dir', null, $channel); - } else { - $this->config->setInstallRoot(false); - $this->_registry = &$this->config->getRegistry(); - if (isset($this->_options['packagingroot'])) { - $installregistry = &new PEAR_Registry($regdir); - if (!$installregistry->channelExists($channel, true)) { - // we need to fake a channel-discover of this channel - $chanobj = $this->_registry->getChannel($channel, true); - $installregistry->addChannel($chanobj); - } - $php_dir = $packrootphp_dir; - } else { - $installregistry = &$this->_registry; - $php_dir = $this->config->get('php_dir', null, $channel); - } - $this->installroot = ''; - } - - // {{{ checks to do when not in "force" mode - if (empty($options['force']) && - (file_exists($this->config->get('php_dir')) && - is_dir($this->config->get('php_dir')))) { - $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); - $instfilelist = $pkg->getInstallationFileList(true); - if (PEAR::isError($instfilelist)) { - return $instfilelist; - } - - // ensure we have the most accurate registry - $installregistry->flushFileMap(); - $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); - if (PEAR::isError($test)) { - return $test; - } - - if (sizeof($test)) { - $pkgs = $this->getInstallPackages(); - $found = false; - foreach ($pkgs as $param) { - if ($pkg->isSubpackageOf($param)) { - $found = true; - break; - } - } - - if ($found) { - // subpackages can conflict with earlier versions of parent packages - $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_array($info)) { - if (strtolower($info[1]) == strtolower($param->getPackage()) && - strtolower($info[0]) == strtolower($param->getChannel()) - ) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } - - unset($test[$file]); - } - } else { - if (strtolower($param->getChannel()) != 'pear.php.net') { - continue; - } - - if (strtolower($info) == strtolower($param->getPackage())) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } - - unset($test[$file]); - } - } - } - - $pfk = &new PEAR_PackageFile($this->config); - $parentpkg = &$pfk->fromArray($parentreg); - $installregistry->updatePackage2($parentpkg); - } - - if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_string($info)) { - // pear.php.net packages are always stored as strings - if (strtolower($info) == strtolower($param->getPackage())) { - // upgrading existing package - unset($test[$file]); - } - } - } - } - - if (count($test)) { - $msg = "$channel/$pkgname: conflicting files found:\n"; - $longest = max(array_map("strlen", array_keys($test))); - $fmt = "%${longest}s (%s)\n"; - foreach ($test as $file => $info) { - if (!is_array($info)) { - $info = array('pear.php.net', $info); - } - $info = $info[0] . '/' . $info[1]; - $msg .= sprintf($fmt, $file, $info); - } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError($msg); - } - - if (!isset($options['soft'])) { - $this->log(0, "WARNING: $msg"); - } - } - } - } - // }}} - - $this->startFileTransaction(); - - if (empty($options['upgrade']) && empty($options['soft'])) { - // checks to do only when installing new packages - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if (empty($options['force']) && $test) { - return $this->raiseError("$channel/$pkgname is already installed"); - } - } else { - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if ($test) { - $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $v2 = $pkg->getVersion(); - $cmp = version_compare("$v1", "$v2", 'gt'); - if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { - return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); - } - - if (empty($options['register-only'])) { - // when upgrading, remove old release's files first: - if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, - true))) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - $backedup = $err; - } - } - } - } - - // {{{ Copy files to dest dir --------------------------------------- - - // info from the package it self we want to access from _installFile - $this->pkginfo = &$pkg; - // used to determine whether we should build any C code - $this->source_files = 0; - - $savechannel = $this->config->get('default_channel'); - if (empty($options['register-only']) && !is_dir($php_dir)) { - if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { - return $this->raiseError("no installation destination directory '$php_dir'\n"); - } - } - - $tmp_path = dirname($descfile); - if (substr($pkgfile, -4) != '.xml') { - $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); - } - - $this->configSet('default_channel', $channel); - // {{{ install files - - $ver = $pkg->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - $filelist = $pkg->getInstallationFilelist(); - } else { - $filelist = $pkg->getFileList(); - } - - if (PEAR::isError($filelist)) { - return $filelist; - } - - $p = &$installregistry->getPackage($pkgname, $channel); - $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false; - - $pkg->resetFilelist(); - $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), - 'version', $pkg->getChannel())); - foreach ($filelist as $file => $atts) { - $this->expectError(PEAR_INSTALLER_FAILED); - if ($pkg->getPackagexmlVersion() == '1.0') { - $res = $this->_installFile($file, $atts, $tmp_path, $options); - } else { - $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); - } - $this->popExpect(); - - if (PEAR::isError($res)) { - if (empty($options['ignore-errors'])) { - $this->rollbackFileTransaction(); - if ($res->getMessage() == "file does not exist") { - $this->raiseError("file $file in package.xml does not exist"); - } - - return $this->raiseError($res); - } - - if (!isset($options['soft'])) { - $this->log(0, "Warning: " . $res->getMessage()); - } - } - - $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; - if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { - // Register files that were installed - $pkg->installedFile($file, $atts); - } - } - // }}} - - // {{{ compile and install source files - if ($this->source_files > 0 && empty($options['nobuild'])) { - if (PEAR::isError($err = - $this->_compileSourceFiles($savechannel, $pkg))) { - return $err; - } - } - // }}} - - if (isset($backedup)) { - $this->_removeBackups($backedup); - } - - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); - } - // }}} - - $ret = false; - $installphase = 'install'; - $oldversion = false; - // {{{ Register that the package is installed ----------------------- - if (empty($options['upgrade'])) { - // if 'force' is used, replace the info in registry - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if (!empty($options['force']) && $test) { - $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $installregistry->deletePackage($pkgname, $usechannel); - } - $ret = $installregistry->addPackage2($pkg); - } else { - if ($dirtree) { - $this->startFileTransaction(); - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - $this->commitFileTransaction(); - } - - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - // new: upgrade installs a package if it isn't installed - if (!$test) { - $ret = $installregistry->addPackage2($pkg); - } else { - if ($usechannel != $channel) { - $installregistry->deletePackage($pkgname, $usechannel); - $ret = $installregistry->addPackage2($pkg); - } else { - $ret = $installregistry->updatePackage2($pkg); - } - $installphase = 'upgrade'; - } - } - - if (!$ret) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError("Adding package $channel/$pkgname to registry failed"); - } - // }}} - - $this->configSet('default_channel', $savechannel); - if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist - if (PEAR_Task_Common::hasPostinstallTasks()) { - PEAR_Task_Common::runPostinstallTasks($installphase); - } - } - - return $pkg->toArray(true); - } - - // }}} - - // {{{ _compileSourceFiles() - /** - * @param string - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function _compileSourceFiles($savechannel, &$filelist) - { - require_once 'PEAR/Builder.php'; - $this->log(1, "$this->source_files source files, building"); - $bob = &new PEAR_Builder($this->ui); - $bob->debug = $this->debug; - $built = $bob->build($filelist, array(&$this, '_buildCallback')); - if (PEAR::isError($built)) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $built; - } - - $this->log(1, "\nBuild process completed successfully"); - foreach ($built as $ext) { - $bn = basename($ext['file']); - list($_ext_name, $_ext_suff) = explode('.', $bn); - if ($_ext_suff == '.so' || $_ext_suff == '.dll') { - if (extension_loaded($_ext_name)) { - $this->raiseError("Extension '$_ext_name' already loaded. " . - 'Please unload it in your php.ini file ' . - 'prior to install or upgrade'); - } - $role = 'ext'; - } else { - $role = 'src'; - } - - $dest = $ext['dest']; - $packagingroot = ''; - if (isset($this->_options['packagingroot'])) { - $packagingroot = $this->_options['packagingroot']; - } - - $copyto = $this->_prependPath($dest, $packagingroot); - $extra = $copyto != $dest ? " as '$copyto'" : ''; - $this->log(1, "Installing '$dest'$extra"); - - $copydir = dirname($copyto); - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (!file_exists($copydir) || !is_dir($copydir)) { - if (!$this->mkDirHier($copydir)) { - return $this->raiseError("failed to mkdir $copydir", - PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ mkdir $copydir"); - } - - if (!@copy($ext['file'], $copyto)) { - return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ cp $ext[file] $copyto"); - $this->addFileOperation('rename', array($ext['file'], $copyto)); - if (!OS_WINDOWS) { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - $this->addFileOperation('chmod', array($mode, $copyto)); - if (!@chmod($copyto, $mode)) { - $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); - } - } - } - - - $data = array( - 'role' => $role, - 'name' => $bn, - 'installed_as' => $dest, - 'php_api' => $ext['php_api'], - 'zend_mod_api' => $ext['zend_mod_api'], - 'zend_ext_api' => $ext['zend_ext_api'], - ); - - if ($filelist->getPackageXmlVersion() == '1.0') { - $filelist->installedFile($bn, $data); - } else { - $filelist->installedFile($bn, array('attribs' => $data)); - } - } - } - - // }}} - function &getUninstallPackages() - { - return $this->_downloadedPackages; - } - // {{{ uninstall() - - /** - * Uninstall a package - * - * This method removes all files installed by the application, and then - * removes any empty directories. - * @param string package name - * @param array Command-line options. Possibilities include: - * - * - installroot: base installation dir, if not the default - * - register-only : update registry but don't remove files - * - nodeps: do not process dependencies of other packages to ensure - * uninstallation does not break things - */ - function uninstall($package, $options = array()) - { - $installRoot = isset($options['installroot']) ? $options['installroot'] : ''; - $this->config->setInstallRoot($installRoot); - - $this->installroot = ''; - $this->_registry = &$this->config->getRegistry(); - if (is_object($package)) { - $channel = $package->getChannel(); - $pkg = $package; - $package = $pkg->getPackage(); - } else { - $pkg = false; - $info = $this->_registry->parsePackageName($package, - $this->config->get('default_channel')); - $channel = $info['channel']; - $package = $info['package']; - } - - $savechannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $channel); - if (!is_object($pkg)) { - $pkg = $this->_registry->getPackage($package, $channel); - } - - if (!$pkg) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError($this->_registry->parsedPackageNameToString( - array( - 'channel' => $channel, - 'package' => $package - ), true) . ' not installed'); - } - - if ($pkg->getInstalledBinary()) { - // this is just an alias for a binary package - return $this->_registry->deletePackage($package, $channel); - } - - $filelist = $pkg->getFilelist(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - - $depchecker = &new PEAR_Dependency2($this->config, $options, - array('channel' => $channel, 'package' => $package), - PEAR_VALIDATE_UNINSTALLING); - $e = $depchecker->validatePackageUninstall($this); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($e); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $e->getMessage()); - } - } elseif (is_array($e)) { - if (!isset($options['soft'])) { - $this->log(0, $e[0]); - } - } - - $this->pkginfo = &$pkg; - // pretty much nothing happens if we are only registering the uninstall - if (empty($options['register-only'])) { - // {{{ Delete the files - $this->startFileTransaction(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { - PEAR::popErrorHandling(); - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - PEAR::popErrorHandling(); - } - - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } - } else { - $this->startFileTransaction(); - $dirtree = $pkg->getDirTree(); - if ($dirtree === false) { - $this->configSet('default_channel', $savechannel); - return $this->_registry->deletePackage($package, $channel); - } - - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } - } - } - // }}} - } - - $this->configSet('default_channel', $savechannel); - // Register that the package is no longer installed - return $this->_registry->deletePackage($package, $channel); - } - - /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * It also removes duplicate dependencies - * @param array an array of PEAR_PackageFile_v[1/2] objects - * @return array|PEAR_Error array of array(packagefilename, package.xml contents) - */ - function sortPackagesForUninstall(&$packages) - { - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); - if (PEAR::isError($this->_dependencyDB)) { - return $this->_dependencyDB; - } - usort($packages, array(&$this, '_sortUninstall')); - } - - function _sortUninstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return -1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return 1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependencyDB->dependsOn($a, $b)) { - return -1; - } - if ($this->_dependencyDB->dependsOn($b, $a)) { - return 1; - } - return 0; - } - - // }}} - // {{{ _sortDirs() - function _sortDirs($a, $b) - { - if (strnatcmp($a, $b) == -1) return 1; - if (strnatcmp($a, $b) == 1) return -1; - return 0; - } - - // }}} - - // {{{ _buildCallback() - - function _buildCallback($what, $data) - { - if (($what == 'cmdoutput' && $this->debug > 1) || - ($what == 'output' && $this->debug > 0)) { - $this->ui->outputData(rtrim($data), 'build'); - } - } - - // }}} -}PEAR-1.9.0/PEAR/PackageFile.php100664 764 764 37466 100664 10741 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PackageFile.php 286670 2009-08-02 14:16:06Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'PEAR/Validate.php'; -/** - * Error code if the package.xml tag does not contain a valid version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); -/** - * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, - * currently - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); -/** - * Abstraction for the package.xml package description file - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile -{ - /** - * @var PEAR_Config - */ - var $_config; - var $_debug; - /** - * Temp directory for uncompressing tgz files. - * @var string|false - */ - var $_tmpdir; - var $_logger = false; - /** - * @var boolean - */ - var $_rawReturn = false; - - /** - * - * @param PEAR_Config $config - * @param ? $debug - * @param string @tmpdir Optional temporary directory for uncompressing - * files - */ - function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) - { - $this->_config = $config; - $this->_debug = $debug; - $this->_tmpdir = $tmpdir; - } - - /** - * Turn off validation - return a parsed package.xml without checking it - * - * This is used by the package-validate command - */ - function rawReturn() - { - $this->_rawReturn = true; - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - /** - * Create a PEAR_PackageFile_Parser_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 - */ - function &parserFactory($version) - { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } - - include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; - $version = $version{0}; - $class = "PEAR_PackageFile_Parser_v$version"; - $a = new $class; - return $a; - } - - /** - * For simpler unit-testing - * @return string - */ - function getClassPrefix() - { - return 'PEAR_PackageFile_v'; - } - - /** - * Create a PEAR_PackageFile_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 - */ - function &factory($version) - { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } - - include_once 'PEAR/PackageFile/v' . $version{0} . '.php'; - $version = $version{0}; - $class = $this->getClassPrefix() . $version; - $a = new $class; - return $a; - } - - /** - * Create a PEAR_PackageFile_v* from its toArray() method - * - * WARNING: no validation is performed, the array is assumed to be valid, - * always parse from xml if you want validation. - * @param array $arr - * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 - * @uses factory() to construct the returned object. - */ - function &fromArray($arr) - { - if (isset($arr['xsdversion'])) { - $obj = &$this->factory($arr['xsdversion']); - if ($this->_logger) { - $obj->setLogger($this->_logger); - } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; - } - - if (isset($arr['package']['attribs']['version'])) { - $obj = &$this->factory($arr['package']['attribs']['version']); - } else { - $obj = &$this->factory('1.0'); - } - - if ($this->_logger) { - $obj->setLogger($this->_logger); - } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; - } - - /** - * Create a PEAR_PackageFile_v* from an XML string. - * @access public - * @param string $data contents of package.xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string $file full path to the package.xml file (and the files - * it references) - * @param string $archive optional name of the archive that the XML was - * extracted from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses parserFactory() to construct a parser to load the package. - */ - function &fromXmlString($data, $state, $file, $archive = false) - { - if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { - if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { - return PEAR::raiseError('package.xml version "' . $packageversion[1] . - '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); - } - - $object = &$this->parserFactory($packageversion[1]); - if ($this->_logger) { - $object->setLogger($this->_logger); - } - - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } - - if ($this->_rawReturn) { - return $pf; - } - - if (!$pf->validate($state)) {; - if ($this->_config->get('verbose') > 0 - && $this->_logger && $pf->getValidationWarnings(false) - ) { - foreach ($pf->getValidationWarnings(false) as $warning) { - $this->_logger->log(0, 'ERROR: ' . $warning['message']); - } - } - - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } - - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } - } - - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 - } - - return $pf; - } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) { - $a = PEAR::raiseError('package.xml file "' . $file . - '" has unsupported package.xml version "' . $packageversion[1] . '"'); - return $a; - } else { - if (!class_exists('PEAR_ErrorStack')) { - require_once 'PEAR/ErrorStack.php'; - } - - PEAR_ErrorStack::staticPush('PEAR_PackageFile', - PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, - 'warning', array('xml' => $data), 'package.xml "' . $file . - '" has no package.xml version'); - $object = &$this->parserFactory('1.0'); - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } - - if ($this->_rawReturn) { - return $pf; - } - - if (!$pf->validate($state)) { - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } - - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } - } - - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 - } - - return $pf; - } - } - - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * @return void - */ - function addTempFile($file) - { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; - } - - /** - * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. - * @access public - * @param string contents of package.xml file - * @param int package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @using Archive_Tar to extract the files - * @using fromPackageFile() to load the package after the package.xml - * file is extracted. - */ - function &fromTgzFile($file, $state) - { - if (!class_exists('Archive_Tar')) { - require_once 'Archive/Tar.php'; - } - - $tar = new Archive_Tar($file); - if ($this->_debug <= 1) { - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - } - - $content = $tar->listContent(); - if ($this->_debug <= 1) { - $tar->popErrorHandling(); - } - - if (!is_array($content)) { - if (is_string($file) && strlen($file < 255) && - (!file_exists($file) || !@is_file($file))) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } - - $file = realpath($file); - $ret = PEAR::raiseError("Could not get contents of package \"$file\"". - '. Invalid tgz file.'); - return $ret; - } - - if (!count($content) && !@is_file($file)) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } - - $xml = null; - $origfile = $file; - foreach ($content as $file) { - $name = $file['filename']; - if ($name == 'package2.xml') { // allow a .tgz to distribute both versions - $xml = $name; - break; - } - - if ($name == 'package.xml') { - $xml = $name; - break; - } elseif (preg_match('/package.xml$/', $name, $match)) { - $xml = $name; - break; - } - } - - if ($this->_tmpdir) { - $tmpdir = $this->_tmpdir; - } else { - $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); - if ($tmpdir === false) { - $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); - return $ret; - } - - PEAR_PackageFile::addTempFile($tmpdir); - } - - $this->_extractErrors(); - PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); - if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { - $extra = implode("\n", $this->_extractErrors()); - if ($extra) { - $extra = ' ' . $extra; - } - - PEAR::staticPopErrorHandling(); - $ret = PEAR::raiseError('could not extract the package.xml file from "' . - $origfile . '"' . $extra); - return $ret; - } - - PEAR::staticPopErrorHandling(); - $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); - return $ret; - } - - /** - * helper for extracting Archive_Tar errors - * @var array - * @access private - */ - var $_extractErrors = array(); - - /** - * helper callback for extracting Archive_Tar errors - * - * @param PEAR_Error|null $err - * @return array - * @access private - */ - function _extractErrors($err = null) - { - static $errors = array(); - if ($err === null) { - $e = $errors; - $errors = array(); - return $e; - } - $errors[] = $err->getMessage(); - } - - /** - * Create a PEAR_PackageFile_v* from a package.xml file. - * - * @access public - * @param string $descfile name of package xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string|false $archive name of the archive this package.xml came - * from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses PEAR_PackageFile::fromXmlString to create the oject after the - * XML is loaded from the package.xml file. - */ - function &fromPackageFile($descfile, $state, $archive = false) - { - $fp = false; - if (is_string($descfile) && strlen($descfile) < 255 && - ( - !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) - || (!$fp = @fopen($descfile, 'r')) - ) - ) { - $a = PEAR::raiseError("Unable to open $descfile"); - return $a; - } - - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); - return $ret; - } - - - /** - * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. - * - * This method is able to extract information about a package from a .tgz - * archive or from a XML package definition file. - * - * @access public - * @param string $info file name - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses fromPackageFile() if the file appears to be XML - * @uses fromTgzFile() to load all non-XML files - */ - function &fromAnyFile($info, $state) - { - if (is_dir($info)) { - $dir_name = realpath($info); - if (file_exists($dir_name . '/package.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); - } elseif (file_exists($dir_name . '/package2.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); - } else { - $info = PEAR::raiseError("No package definition found in '$info' directory"); - } - - return $info; - } - - $fp = false; - if (is_string($info) && strlen($info) < 255 && - (file_exists($info) || ($fp = @fopen($info, 'r'))) - ) { - - if ($fp) { - fclose($fp); - } - - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = &PEAR_PackageFile::fromPackageFile($info, $state); - } elseif ($tmp == '.tar' || $tmp == '.tgz') { - $info = &PEAR_PackageFile::fromTgzFile($info, $state); - } else { - $fp = fopen($info, 'r'); - $test = fread($fp, 5); - fclose($fp); - if ($test == ' - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Packager.php 286809 2009-08-04 15:10:26Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Common.php'; -require_once 'PEAR/PackageFile.php'; -require_once 'System.php'; - -/** - * Administration class used to make a PEAR release tarball. - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Packager extends PEAR_Common -{ - /** - * @var PEAR_Registry - */ - var $_registry; - - function package($pkgfile = null, $compress = true, $pkg2 = null) - { - // {{{ validate supplied package.xml file - if (empty($pkgfile)) { - $pkgfile = 'package.xml'; - } - - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pkg = &new PEAR_PackageFile($this->config, $this->debug); - $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL); - $main = &$pf; - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $error) { - $this->log(0, 'Error: ' . $error['message']); - } - } - - $this->log(0, $pf->getMessage()); - return $this->raiseError("Cannot package, errors in package file"); - } - - foreach ($pf->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); - } - - // }}} - if ($pkg2) { - $this->log(0, 'Attempting to process the second package file'); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf2)) { - if (is_array($pf2->getUserInfo())) { - foreach ($pf2->getUserInfo() as $error) { - $this->log(0, 'Error: ' . $error['message']); - } - } - $this->log(0, $pf2->getMessage()); - return $this->raiseError("Cannot package, errors in second package file"); - } - - foreach ($pf2->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); - } - - if ($pf2->getPackagexmlVersion() == '2.0' || - $pf2->getPackagexmlVersion() == '2.1' - ) { - $main = &$pf2; - $other = &$pf; - } else { - $main = &$pf; - $other = &$pf2; - } - - if ($main->getPackagexmlVersion() != '2.0' && - $main->getPackagexmlVersion() != '2.1') { - return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' . - 'only package together a package.xml 1.0 and package.xml 2.0'); - } - - if ($other->getPackagexmlVersion() != '1.0') { - return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' . - 'only package together a package.xml 1.0 and package.xml 2.0'); - } - } - - $main->setLogger($this); - if (!$main->validate(PEAR_VALIDATE_PACKAGING)) { - foreach ($main->getValidationWarnings() as $warning) { - $this->log(0, 'Error: ' . $warning['message']); - } - return $this->raiseError("Cannot package, errors in package"); - } - - foreach ($main->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); - } - - if ($pkg2) { - $other->setLogger($this); - $a = false; - if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) { - foreach ($other->getValidationWarnings() as $warning) { - $this->log(0, 'Error: ' . $warning['message']); - } - - foreach ($main->getValidationWarnings() as $warning) { - $this->log(0, 'Error: ' . $warning['message']); - } - - if ($a) { - return $this->raiseError('The two package.xml files are not equivalent!'); - } - - return $this->raiseError("Cannot package, errors in package"); - } - - foreach ($other->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); - } - - $gen = &$main->getDefaultGenerator(); - $tgzfile = $gen->toTgz2($this, $other, $compress); - if (PEAR::isError($tgzfile)) { - return $tgzfile; - } - - $dest_package = basename($tgzfile); - $pkgdir = dirname($pkgfile); - - // TAR the Package ------------------------------------------- - $this->log(1, "Package $dest_package done"); - if (file_exists("$pkgdir/CVS/Root")) { - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); - $cvstag = "RELEASE_$cvsversion"; - $this->log(1, 'Tag the released code with "pear cvstag ' . - $main->getPackageFile() . '"'); - $this->log(1, "(or set the CVS tag $cvstag by hand)"); - } elseif (file_exists("$pkgdir/.svn")) { - $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion()); - $svntag = $pf->getName() . "-$svnversion"; - $this->log(1, 'Tag the released code with "pear svntag ' . - $main->getPackageFile() . '"'); - $this->log(1, "(or set the SVN tag $svntag by hand)"); - } - } else { // this branch is executed for single packagefile packaging - $gen = &$pf->getDefaultGenerator(); - $tgzfile = $gen->toTgz($this, $compress); - if (PEAR::isError($tgzfile)) { - $this->log(0, $tgzfile->getMessage()); - return $this->raiseError("Cannot package, errors in package"); - } - - $dest_package = basename($tgzfile); - $pkgdir = dirname($pkgfile); - - // TAR the Package ------------------------------------------- - $this->log(1, "Package $dest_package done"); - if (file_exists("$pkgdir/CVS/Root")) { - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); - $cvstag = "RELEASE_$cvsversion"; - $this->log(1, "Tag the released code with `pear cvstag $pkgfile'"); - $this->log(1, "(or set the CVS tag $cvstag by hand)"); - } elseif (file_exists("$pkgdir/.svn")) { - $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion()); - $svntag = $pf->getName() . "-$svnversion"; - $this->log(1, "Tag the released code with `pear svntag $pkgfile'"); - $this->log(1, "(or set the SVN tag $svntag by hand)"); - } - } - - return $dest_package; - } -}PEAR-1.9.0/PEAR/Registry.php100664 764 764 224124 100664 10423 - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Registry.php 287555 2009-08-21 21:27:27Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * for PEAR_Error - */ -require_once 'PEAR.php'; -require_once 'PEAR/DependencyDB.php'; - -define('PEAR_REGISTRY_ERROR_LOCK', -2); -define('PEAR_REGISTRY_ERROR_FORMAT', -3); -define('PEAR_REGISTRY_ERROR_FILE', -4); -define('PEAR_REGISTRY_ERROR_CONFLICT', -5); -define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); - -/** - * Administration class used to maintain the installed package database. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Registry extends PEAR -{ - /** - * File containing all channel information. - * @var string - */ - var $channels = ''; - - /** Directory where registry files are stored. - * @var string - */ - var $statedir = ''; - - /** File where the file map is stored - * @var string - */ - var $filemap = ''; - - /** Directory where registry files for channels are stored. - * @var string - */ - var $channelsdir = ''; - - /** Name of file used for locking the registry - * @var string - */ - var $lockfile = ''; - - /** File descriptor used during locking - * @var resource - */ - var $lock_fp = null; - - /** Mode used during locking - * @var int - */ - var $lock_mode = 0; // XXX UNUSED - - /** Cache of package information. Structure: - * array( - * 'package' => array('id' => ... ), - * ... ) - * @var array - */ - var $pkginfo_cache = array(); - - /** Cache of file map. Structure: - * array( '/path/to/file' => 'package', ... ) - * @var array - */ - var $filemap_cache = array(); - - /** - * @var false|PEAR_ChannelFile - */ - var $_pearChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_peclChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_docChannel; - - /** - * @var PEAR_DependencyDB - */ - var $_dependencyDB; - - /** - * @var PEAR_Config - */ - var $_config; - - /** - * PEAR_Registry constructor. - * - * @param string (optional) PEAR install directory (for .php files) - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * - * @access public - */ - function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, - $pecl_channel = false) - { - parent::PEAR(); - $this->setInstallDir($pear_install_dir); - $this->_pearChannel = $pear_channel; - $this->_peclChannel = $pecl_channel; - $this->_config = false; - } - - function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) - { - $ds = DIRECTORY_SEPARATOR; - $this->install_dir = $pear_install_dir; - $this->channelsdir = $pear_install_dir.$ds.'.channels'; - $this->statedir = $pear_install_dir.$ds.'.registry'; - $this->filemap = $pear_install_dir.$ds.'.filemap'; - $this->lockfile = $pear_install_dir.$ds.'.lock'; - } - - function hasWriteAccess() - { - if (!file_exists($this->install_dir)) { - $dir = $this->install_dir; - while ($dir && $dir != '.') { - $olddir = $dir; - $dir = dirname($dir); - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - - if ($dir == $olddir) { // this can happen in safe mode - return @is_writable($dir); - } - } - - return false; - } - - return is_writeable($this->install_dir); - } - - function setConfig(&$config, $resetInstallDir = true) - { - $this->_config = &$config; - if ($resetInstallDir) { - $this->setInstallDir($config->get('php_dir')); - } - } - - function _initializeChannelDirs() - { - static $running = false; - if (!$running) { - $running = true; - $ds = DIRECTORY_SEPARATOR; - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $pear_channel = $this->_pearChannel; - if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setAlias('pear'); - $pear_channel->setServer('pear.php.net'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); - //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/'); - } else { - $pear_channel->setServer('pear.php.net'); - $pear_channel->setAlias('pear'); - } - - $pear_channel->validate(); - $this->_addChannel($pear_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { - $pecl_channel = $this->_peclChannel; - if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $pecl_channel = new PEAR_ChannelFile; - $pecl_channel->setAlias('pecl'); - $pecl_channel->setServer('pecl.php.net'); - $pecl_channel->setSummary('PHP Extension Community Library'); - $pecl_channel->setDefaultPEARProtocols(); - $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - } else { - $pecl_channel->setServer('pecl.php.net'); - $pecl_channel->setAlias('pecl'); - } - - $pecl_channel->validate(); - $this->_addChannel($pecl_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { - $doc_channel = $this->_docChannel; - if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setAlias('phpdocs'); - $doc_channel->setServer('doc.php.net'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); - } else { - $doc_channel->setServer('doc.php.net'); - $doc_channel->setAlias('doc'); - } - - $doc_channel->validate(); - $this->_addChannel($doc_channel); - } - - if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - $this->_addChannel($private); - } - $this->_rebuildFileMap(); - } - - $running = false; - } - } - - function _initializeDirs() - { - $ds = DIRECTORY_SEPARATOR; - // XXX Compatibility code should be removed in the future - // rename all registry files if any to lowercase - if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && - $handle = opendir($this->statedir)) { - $dest = $this->statedir . $ds; - while (false !== ($file = readdir($handle))) { - if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { - rename($dest . $file, $dest . strtolower($file)); - } - } - closedir($handle); - } - - $this->_initializeChannelDirs(); - if (!file_exists($this->filemap)) { - $this->_rebuildFileMap(); - } - $this->_initializeDepDB(); - } - - function _initializeDepDB() - { - if (!isset($this->_dependencyDB)) { - static $initializing = false; - if (!$initializing) { - $initializing = true; - if (!$this->_config) { // never used? - $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; - $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . - $file); - $this->_config->setRegistry($this); - $this->_config->set('php_dir', $this->install_dir); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - // attempt to recover by removing the dep db - if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb')) { - @unlink($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - echo $this->_dependencyDB->getMessage(); - echo 'Unrecoverable error'; - exit(1); - } - } - - $initializing = false; - } - } - } - - /** - * PEAR_Registry destructor. Makes sure no locks are forgotten. - * - * @access private - */ - function _PEAR_Registry() - { - parent::_PEAR(); - if (is_resource($this->lock_fp)) { - $this->_unlock(); - } - } - - /** - * Make sure the directory where we keep registry files exists. - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertStateDir($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_assertChannelStateDir($channel); - } - - static $init = false; - if (!file_exists($this->statedir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $this->statedir))) { - return $this->raiseError("could not create directory '{$this->statedir}'"); - } - $init = true; - } elseif (!is_dir($this->statedir)) { - return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . - 'it already exists and is not a directory'); - } - - $ds = DIRECTORY_SEPARATOR; - if (!file_exists($this->channelsdir)) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - $init = true; - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . - 'it already exists and is not a directory'); - } - - if ($init) { - static $running = false; - if (!$running) { - $running = true; - $this->_initializeDirs(); - $running = false; - $init = false; - } - } else { - $this->_initializeDepDB(); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files exists for a non-standard channel. - * - * @param string channel name - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelStateDir($channel) - { - $ds = DIRECTORY_SEPARATOR; - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - return $this->_assertStateDir($channel); - } - - $channelDir = $this->_channelDirectoryName($channel); - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - - if (!file_exists($channelDir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $channelDir))) { - return $this->raiseError("could not create directory '" . $channelDir . - "'"); - } - } elseif (!is_dir($channelDir)) { - return $this->raiseError("could not create directory '" . $channelDir . - "', already exists and is not a directory"); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files for channels exists - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelDir() - { - if (!file_exists($this->channelsdir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir))) { - return $this->raiseError("could not create directory '{$this->channelsdir}'"); - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "', it already exists and is not a directory"); - } - - if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { - return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); - } - } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "/.alias', it already exists and is not a directory"); - } - - return true; - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _packageFileName($package, $channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . - strtolower($package) . '.reg'; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; - } - - /** - * Get the name of the file where data for a given channel is stored. - * @param string channel name - * @return string registry file name - */ - function _channelFileName($channel, $noaliases = false) - { - if (!$noaliases) { - if (file_exists($this->_getChannelAliasFileName($channel))) { - $channel = implode('', file($this->_getChannelAliasFileName($channel))); - } - } - return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', - strtolower($channel)) . '.reg'; - } - - /** - * @param string - * @return string - */ - function _getChannelAliasFileName($alias) - { - return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . - DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; - } - - /** - * Get the name of a channel from its alias - */ - function _getChannelFromAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear.php.net'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl.php.net'; - } - - if ($channel == 'doc.php.net') { - return 'doc.php.net'; - } - - if ($channel == '__uri') { - return '__uri'; - } - - return false; - } - - $channel = strtolower($channel); - if (file_exists($this->_getChannelAliasFileName($channel))) { - // translate an alias to an actual channel - return implode('', file($this->_getChannelAliasFileName($channel))); - } - - return $channel; - } - - /** - * Get the alias of a channel from its alias or its name - */ - function _getAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl'; - } - - if ($channel == 'doc.php.net') { - return 'phpdocs'; - } - - return false; - } - - $channel = $this->_getChannel($channel); - if (PEAR::isError($channel)) { - return $channel; - } - - return $channel->getAlias(); - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _channelDirectoryName($channel) - { - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return $this->statedir; - } - - $ch = $this->_getChannelFromAlias($channel); - if (!$ch) { - $ch = $channel; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . - str_replace('/', '_', $ch)); - } - - function _openPackageFile($package, $mode, $channel = false) - { - if (!$this->_assertStateDir($channel)) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_packageFileName($package, $channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closePackageFile($fp) - { - fclose($fp); - } - - function _openChannelFile($channel, $mode) - { - if (!$this->_assertChannelDir()) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_channelFileName($channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closeChannelFile($fp) - { - fclose($fp); - } - - function _rebuildFileMap() - { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'PEAR/Installer/Role.php'; - } - - $channels = $this->_listAllPackages(); - $files = array(); - foreach ($channels as $channel => $packages) { - foreach ($packages as $package) { - $version = $this->_packageInfo($package, 'version', $channel); - $filelist = $this->_packageInfo($package, 'filelist', $channel); - if (!is_array($filelist)) { - continue; - } - - foreach ($filelist as $name => $attrs) { - if (isset($attrs['attribs'])) { - $attrs = $attrs['attribs']; - } - - // it is possible for conflicting packages in different channels to - // conflict with data files/doc files - if ($name == 'dirtree') { - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = $package; - } - - if (isset($attrs['baseinstalldir'])) { - $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; - } else { - $file = $name; - } - - $file = preg_replace(',^/+,', '', $file); - if ($channel != 'pear.php.net') { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = array(strtolower($channel), - strtolower($package)); - } else { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = strtolower($package); - } - } - } - } - - - $this->_assertStateDir(); - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->filemap, 'wb'); - if (!$fp) { - return false; - } - - $this->filemap_cache = $files; - fwrite($fp, serialize($files)); - fclose($fp); - return true; - } - - function _readFileMap() - { - if (!file_exists($this->filemap)) { - return array(); - } - - $fp = @fopen($this->filemap, 'r'); - if (!$fp) { - return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); - } - - clearstatcache(); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - $fsize = filesize($this->filemap); - fclose($fp); - $data = file_get_contents($this->filemap); - set_magic_quotes_runtime($rt); - $tmp = unserialize($data); - if (!$tmp && $fsize > 7) { - return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); - } - - $this->filemap_cache = $tmp; - return true; - } - - /** - * Lock the registry. - * - * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. - * See flock manual for more information. - * - * @return bool TRUE on success, FALSE if locking failed, or a - * PEAR error if some other error occurs (such as the - * lock file not being writable). - * - * @access private - */ - function _lock($mode = LOCK_EX) - { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->lock_fp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - if (!$this->_assertStateDir()) { - if ($mode == LOCK_EX) { - return $this->raiseError('Registry directory is not writeable by the current user'); - } - - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH || $mode === LOCK_UN) { - if (!file_exists($this->lockfile)) { - touch($this->lockfile); - } - $open_mode = 'r'; - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = @fopen($this->lockfile, $open_mode); - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = null; - return $this->raiseError("could not create lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->lock_fp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - //is resource at this point, close it on error. - fclose($this->lock_fp); - $this->lock_fp = null; - return $this->raiseError("could not acquire $str lock ($this->lockfile)", - PEAR_REGISTRY_ERROR_LOCK); - } - - return true; - } - - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->lock_fp)) { - fclose($this->lock_fp); - } - - $this->lock_fp = null; - return $ret; - } - - function _packageExists($package, $channel = false) - { - return file_exists($this->_packageFileName($package, $channel)); - } - - /** - * Determine whether a channel exists in the registry - * - * @param string Channel name - * @param bool if true, then aliases will be ignored - * @return boolean - */ - function _channelExists($channel, $noaliases = false) - { - $a = file_exists($this->_channelFileName($channel, $noaliases)); - if (!$a && $channel == 'pear.php.net') { - return true; - } - - if (!$a && $channel == 'pecl.php.net') { - return true; - } - - if (!$a && $channel == 'doc.php.net') { - return true; - } - - return $a; - } - - /** - * Determine whether a mirror exists within the deafult channel in the registry - * - * @param string Channel name - * @param string Mirror name - * - * @return boolean - */ - function _mirrorExists($channel, $mirror) - { - $data = $this->_channelInfo($channel); - if (!isset($data['servers']['mirror'])) { - return false; - } - - foreach ($data['servers']['mirror'] as $m) { - if ($m['attribs']['host'] == $mirror) { - return true; - } - } - - return false; - } - - /** - * @param PEAR_ChannelFile Channel object - * @param donotuse - * @param string Last-Modified HTTP tag from remote request - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function _addChannel($channel, $update = false, $lastmodified = false) - { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - - if (file_exists($this->_channelFileName($channel->getName()))) { - if (!$update) { - return false; - } - - $checker = $this->_getChannel($channel->getName()); - if (PEAR::isError($checker)) { - return $checker; - } - - if ($channel->getAlias() != $checker->getAlias()) { - if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { - @unlink($this->_getChannelAliasFileName($checker->getAlias())); - } - } - } else { - if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { - return false; - } - } - - $ret = $this->_assertChannelDir(); - if (PEAR::isError($ret)) { - return $ret; - } - - $ret = $this->_assertChannelStateDir($channel->getName()); - if (PEAR::isError($ret)) { - return $ret; - } - - if ($channel->getAlias() != $channel->getName()) { - if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && - $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { - $channel->setAlias($channel->getName()); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); - if (!$fp) { - return false; - } - - fwrite($fp, $channel->getName()); - fclose($fp); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); - if (!$fp) { - return false; - } - - $info = $channel->toArray(); - if ($lastmodified) { - $info['_lastmodified'] = $lastmodified; - } else { - $info['_lastmodified'] = date('r'); - } - - fwrite($fp, serialize($info)); - fclose($fp); - return true; - } - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function _deleteChannel($channel) - { - if (!is_string($channel)) { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - $channel = $channel->getName(); - } - - if ($this->_getChannelFromAlias($channel) == '__uri') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - return false; - } - - if (!$this->_channelExists($channel)) { - return false; - } - - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return false; - } - - $channel = $this->_getChannelFromAlias($channel); - if ($channel == 'pear.php.net') { - return false; - } - - $test = $this->_listChannelPackages($channel); - if (count($test)) { - return false; - } - - $test = @rmdir($this->_channelDirectoryName($channel)); - if (!$test) { - return false; - } - - $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); - if (file_exists($file)) { - $test = @unlink($file); - if (!$test) { - return false; - } - } - - $file = $this->_channelFileName($channel); - $ret = true; - if (file_exists($file)) { - $ret = @unlink($file); - } - - return $ret; - } - - /** - * Determine whether a channel exists in the registry - * @param string Channel Alias - * @return boolean - */ - function _isChannelAlias($alias) - { - return file_exists($this->_getChannelAliasFileName($alias)); - } - - /** - * @param string|null - * @param string|null - * @param string|null - * @return array|null - * @access private - */ - function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if ($package === null) { - if ($channel === null) { - $channels = $this->_listChannels(); - $ret = array(); - foreach ($channels as $channel) { - $channel = strtolower($channel); - $ret[$channel] = array(); - $packages = $this->_listPackages($channel); - foreach ($packages as $package) { - $ret[$channel][] = $this->_packageInfo($package, null, $channel); - } - } - - return $ret; - } - - $ps = $this->_listPackages($channel); - if (!count($ps)) { - return array(); - } - return array_map(array(&$this, '_packageInfo'), - $ps, array_fill(0, count($ps), null), - array_fill(0, count($ps), $channel)); - } - - $fp = $this->_openPackageFile($package, 'r', $channel); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closePackageFile($fp); - $data = file_get_contents($this->_packageFileName($package, $channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - if ($key === null) { - return $data; - } - - // compatibility for package.xml version 2.0 - if (isset($data['old'][$key])) { - return $data['old'][$key]; - } - - if (isset($data[$key])) { - return $data[$key]; - } - - return null; - } - - /** - * @param string Channel name - * @param bool whether to strictly retrieve info of channels, not just aliases - * @return array|null - */ - function _channelInfo($channel, $noaliases = false) - { - if (!$this->_channelExists($channel, $noaliases)) { - return null; - } - - $fp = $this->_openChannelFile($channel, 'r'); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closeChannelFile($fp); - $data = file_get_contents($this->_channelFileName($channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - return $data; - } - - function _listChannels() - { - $channellist = array(); - if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { - return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); - } - - $dp = opendir($this->channelsdir); - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - if ($ent == '__uri.reg') { - $channellist[] = '__uri'; - continue; - } - - $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); - } - - closedir($dp); - if (!in_array('pear.php.net', $channellist)) { - $channellist[] = 'pear.php.net'; - } - - if (!in_array('pecl.php.net', $channellist)) { - $channellist[] = 'pecl.php.net'; - } - - if (!in_array('doc.php.net', $channellist)) { - $channellist[] = 'doc.php.net'; - } - - - if (!in_array('__uri', $channellist)) { - $channellist[] = '__uri'; - } - - natsort($channellist); - return $channellist; - } - - function _listPackages($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_listChannelPackages($channel); - } - - if (!file_exists($this->statedir) || !is_dir($this->statedir)) { - return array(); - } - - $pkglist = array(); - $dp = opendir($this->statedir); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - $pkglist[] = substr($ent, 0, -4); - } - closedir($dp); - return $pkglist; - } - - function _listChannelPackages($channel) - { - $pkglist = array(); - if (!file_exists($this->_channelDirectoryName($channel)) || - !is_dir($this->_channelDirectoryName($channel))) { - return array(); - } - - $dp = opendir($this->_channelDirectoryName($channel)); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - $pkglist[] = substr($ent, 0, -4); - } - - closedir($dp); - return $pkglist; - } - - function _listAllPackages() - { - $ret = array(); - foreach ($this->_listChannels() as $channel) { - $ret[$channel] = $this->_listPackages($channel); - } - - return $ret; - } - - /** - * Add an installed package to the registry - * @param string package name - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - * @access private - */ - function _addPackage($package, $info) - { - if ($this->_packageExists($package)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb'); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($info['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _addPackage2($info) - { - if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { - return false; - } - - if (!$info->validate()) { - if (class_exists('PEAR_Common')) { - $ui = PEAR_Frontend::singleton(); - if ($ui) { - foreach ($info->getValidationWarnings() as $err) { - $ui->log($err['message'], true); - } - } - } - return false; - } - - $channel = $info->getChannel(); - $package = $info->getPackage(); - $save = $info; - if ($this->_packageExists($package, $channel)) { - return false; - } - - if (!$this->_channelExists($channel, true)) { - return false; - } - - $info = $info->toArray(true); - if (!$info) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb', $channel); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param array parsed package.xml 1.0 - * @param bool this parameter is only here for BC. Don't use it. - * @access private - */ - function _updatePackage($package, $info, $merge = true) - { - $oldinfo = $this->_packageInfo($package); - if (empty($oldinfo)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'w'); - if ($fp === null) { - return false; - } - - if (is_object($info)) { - $info = $info->toArray(); - } - $info['_lastmodified'] = time(); - - $newinfo = $info; - if ($merge) { - $info = array_merge($oldinfo, $info); - } else { - $diff = $info; - } - - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($newinfo['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _updatePackage2($info) - { - if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { - return false; - } - - $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); - if ($fp === null) { - return false; - } - - $save = $info; - $info = $save->getArray(true); - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param string Channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - * @access private - */ - function &_getPackage($package, $channel = 'pear.php.net') - { - $info = $this->_packageInfo($package, null, $channel); - if ($info === null) { - return $info; - } - - $a = $this->_config; - if (!$a) { - $this->_config = &new PEAR_Config; - $this->_config->set('php_dir', $this->statedir); - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - - $pkg = &new PEAR_PackageFile($this->_config); - $pf = &$pkg->fromArray($info); - return $pf; - } - - /** - * @param string channel name - * @param bool whether to strictly retrieve channel names - * @return PEAR_ChannelFile|PEAR_Error - * @access private - */ - function &_getChannel($channel, $noaliases = false) - { - $ch = false; - if ($this->_channelExists($channel, $noaliases)) { - $chinfo = $this->_channelInfo($channel, $noaliases); - if ($chinfo) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); - } - } - - if ($ch) { - if ($ch->validate()) { - return $ch; - } - - foreach ($ch->getErrors(true) as $err) { - $message = $err['message'] . "\n"; - } - - $ch = PEAR::raiseError($message); - return $ch; - } - - if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setServer('pear.php.net'); - $pear_channel->setAlias('pear'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setServer('pecl.php.net'); - $pear_channel->setAlias('pecl'); - $pear_channel->setSummary('PHP Extension Community Library'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setServer('doc.php.net'); - $doc_channel->setAlias('phpdocs'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); - return $doc_channel; - } - - - if ($this->_getChannelFromAlias($channel) == '__uri') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - return $private; - } - - return $ch; - } - - /** - * @param string Package name - * @param string Channel name - * @return bool - */ - function packageExists($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageExists($package, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - - // {{{ channelExists() - - /** - * @param string channel name - * @param bool if true, then aliases will be ignored - * @return bool - */ - function channelExists($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelExists($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - /** - * @param string channel name mirror is in - * @param string mirror name - * - * @return bool - */ - function mirrorExists($channel, $mirror) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - - $ret = $this->_mirrorExists($channel, $mirror); - $this->_unlock(); - return $ret; - } - - // {{{ isAlias() - - /** - * Determines whether the parameter is an alias of a channel - * @param string - * @return bool - */ - function isAlias($alias) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_isChannelAlias($alias); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ packageInfo() - - /** - * @param string|null - * @param string|null - * @param string - * @return array|null - */ - function packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageInfo($package, $key, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ channelInfo() - - /** - * Retrieve a raw array of channel data. - * - * Do not use this, instead use {@link getChannel()} for normal - * operations. Array structure is undefined in this method - * @param string channel name - * @param bool whether to strictly retrieve information only on non-aliases - * @return array|null|PEAR_Error - */ - function channelInfo($channel = null, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelInfo($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - /** - * @param string - */ - function channelName($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getChannelFromAlias($channel); - $this->_unlock(); - return $ret; - } - - /** - * @param string - */ - function channelAlias($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getAlias($channel); - $this->_unlock(); - return $ret; - } - // {{{ listPackages() - - function listPackages($channel = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listPackages($channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listAllPackages() - - function listAllPackages() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listAllPackages(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listChannel() - - function listChannels() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listChannels(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ addPackage() - - /** - * Add an installed package to the registry - * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object - * that will be passed to {@link addPackage2()} - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - */ - function addPackage($package, $info) - { - if (is_object($info)) { - return $this->addPackage2($info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage($package, $info); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($info); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ addPackage2() - - function addPackage2($info) - { - if (!is_object($info)) { - return $this->addPackage($info['package'], $info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - return $ret; - } - - // }}} - // {{{ updateChannel() - - /** - * For future expandibility purposes, separate this - * @param PEAR_ChannelFile - */ - function updateChannel($channel, $lastmodified = null) - { - if ($channel->getName() == '__uri') { - return false; - } - return $this->addChannel($channel, $lastmodified, true); - } - - // }}} - // {{{ deleteChannel() - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function deleteChannel($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_deleteChannel($channel); - $this->_unlock(); - if ($ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - - return $ret; - } - - // }}} - // {{{ addChannel() - - /** - * @param PEAR_ChannelFile Channel object - * @param string Last-Modified header from HTTP for caching - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function addChannel($channel, $lastmodified = false, $update = false) - { - if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) { - return false; - } - - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_addChannel($channel, $update, $lastmodified); - $this->_unlock(); - if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - - return $ret; - } - - // }}} - // {{{ deletePackage() - - function deletePackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $file = $this->_packageFileName($package, $channel); - $ret = file_exists($file) ? @unlink($file) : false; - $this->_rebuildFileMap(); - $this->_unlock(); - $p = array('channel' => $channel, 'package' => $package); - $this->_dependencyDB->uninstallPackage($p); - return $ret; - } - - // }}} - // {{{ updatePackage() - - function updatePackage($package, $info, $merge = true) - { - if (is_object($info)) { - return $this->updatePackage2($info, $merge); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_updatePackage($package, $info, $merge); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($this->packageInfo($package)); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ updatePackage2() - - function updatePackage2($info) - { - - if (!is_object($info)) { - return $this->updatePackage($info['package'], $info, $merge); - } - - if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { - return false; - } - - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_updatePackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - - return $ret; - } - - // }}} - // {{{ getChannel() - /** - * @param string channel name - * @param bool whether to strictly return raw channels (no aliases) - * @return PEAR_ChannelFile|PEAR_Error - */ - function &getChannel($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = &$this->_getChannel($channel, $noaliases); - $this->_unlock(); - if (!$ret) { - return PEAR::raiseError('Unknown channel: ' . $channel); - } - return $ret; - } - - // }}} - // {{{ getPackage() - /** - * @param string package name - * @param string channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - */ - function &getPackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $pf = &$this->_getPackage($package, $channel); - $this->_unlock(); - return $pf; - } - - // }}} - - /** - * Get PEAR_PackageFile_v[1/2] objects representing the contents of - * a dependency group that are installed. - * - * This is used at uninstall-time - * @param array - * @return array|false - */ - function getInstalledGroup($group) - { - $ret = array(); - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - foreach ($group['package'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } - foreach ($group['subpackage'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (!count($ret)) { - return false; - } - return $ret; - } - - // {{{ getChannelValidator() - /** - * @param string channel name - * @return PEAR_Validate|false - */ - function &getChannelValidator($channel) - { - $chan = $this->getChannel($channel); - if (PEAR::isError($chan)) { - return $chan; - } - $val = $chan->getValidationObject(); - return $val; - } - // }}} - // {{{ getChannels() - /** - * @param string channel name - * @return array an array of PEAR_ChannelFile objects representing every installed channel - */ - function &getChannels() - { - $ret = array(); - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - foreach ($this->_listChannels() as $channel) { - $e = &$this->_getChannel($channel); - if (!$e || PEAR::isError($e)) { - continue; - } - $ret[] = $e; - } - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ checkFileMap() - - /** - * Test whether a file or set of files belongs to a package. - * - * If an array is passed in - * @param string|array file path, absolute or relative to the pear - * install dir - * @param string|array name of PEAR package or array('package' => name, 'channel' => - * channel) of a package that will be ignored - * @param string API version - 1.1 will exclude any files belonging to a package - * @param array private recursion variable - * @return array|false which package and channel the file belongs to, or an empty - * string if the file does not belong to an installed package, - * or belongs to the second parameter's package - */ - function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) - { - if (is_array($path)) { - static $notempty; - if (empty($notempty)) { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'PEAR/Installer/Role.php'; - } - $notempty = create_function('$a','return !empty($a);'); - } - $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) - : strtolower($package); - $pkgs = array(); - foreach ($path as $name => $attrs) { - if (is_array($attrs)) { - if (isset($attrs['install-as'])) { - $name = $attrs['install-as']; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; - } - if (isset($attrs['baseinstalldir'])) { - $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; - } - } - $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); - if (PEAR::isError($pkgs[$name])) { - return $pkgs[$name]; - } - } - return array_filter($pkgs, $notempty); - } - if (empty($this->filemap_cache)) { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $err = $this->_readFileMap(); - $this->_unlock(); - if (PEAR::isError($err)) { - return $err; - } - } - if (!$attrs) { - $attrs = array('role' => 'php'); // any old call would be for PHP role only - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - $l = strlen($this->install_dir); - if (substr($path, 0, $l) == $this->install_dir) { - $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - return false; - } - - // }}} - // {{{ flush() - /** - * Force a reload of the filemap - * @since 1.5.0RC3 - */ - function flushFileMap() - { - $this->filemap_cache = null; - clearstatcache(); // ensure that the next read gets the full, current filemap - } - - // }}} - // {{{ apiVersion() - /** - * Get the expected API version. Channels API is version 1.1, as it is backwards - * compatible with 1.0 - * @return string - */ - function apiVersion() - { - return '1.1'; - } - // }}} - - - /** - * Parse a package name, or validate a parsed package name array - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',] - * ['group' => 'groupname']) - * or a string of format - * [channel://][channame/]pname[-version|-state][/group=groupname] - * @return array|PEAR_Error - */ - function parsePackageName($param, $defaultchannel = 'pear.php.net') - { - $saveparam = $param; - if (is_array($param)) { - // convert to string for error messages - $saveparam = $this->parsedPackageNameToString($param); - // process the array - if (!isset($param['package'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in index "param"', - 'package', null, null, $param); - } - if (!isset($param['uri'])) { - if (!isset($param['channel'])) { - $param['channel'] = $defaultchannel; - } - } else { - $param['channel'] = '__uri'; - } - } else { - $components = @parse_url((string) $param); - if (isset($components['scheme'])) { - if ($components['scheme'] == 'http') { - // uri package - $param = array('uri' => $param, 'channel' => '__uri'); - } elseif($components['scheme'] != 'channel') { - return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . - 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); - } - } - if (!isset($components['path'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in "' . $param . '"', - 'package', null, null, $param); - } - if (isset($components['host'])) { - // remove the leading "/" - $components['path'] = substr($components['path'], 1); - } - if (!isset($components['scheme'])) { - if (strpos($components['path'], '/') !== false) { - if ($components['path']{0} == '/') { - return PEAR::raiseError('parsePackageName(): this is not ' . - 'a package name, it begins with "/" in "' . $param . '"', - 'invalid', null, null, $param); - } - $parts = explode('/', $components['path']); - $components['host'] = array_shift($parts); - if (count($parts) > 1) { - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } else { - $components['path'] = implode('/', $parts); - } - } else { - $components['host'] = $defaultchannel; - } - } else { - if (strpos($components['path'], '/')) { - $parts = explode('/', $components['path']); - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } - } - - if (is_array($param)) { - $param['package'] = $components['path']; - } else { - $param = array( - 'package' => $components['path'] - ); - if (isset($components['host'])) { - $param['channel'] = $components['host']; - } - } - if (isset($components['fragment'])) { - $param['group'] = $components['fragment']; - } - if (isset($components['user'])) { - $param['user'] = $components['user']; - } - if (isset($components['pass'])) { - $param['pass'] = $components['pass']; - } - if (isset($components['query'])) { - parse_str($components['query'], $param['opts']); - } - // check for extension - $pathinfo = pathinfo($param['package']); - if (isset($pathinfo['extension']) && - in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { - $param['extension'] = $pathinfo['extension']; - $param['package'] = substr($pathinfo['basename'], 0, - strlen($pathinfo['basename']) - 4); - } - // check for version - if (strpos($param['package'], '-')) { - $test = explode('-', $param['package']); - if (count($test) != 2) { - return PEAR::raiseError('parsePackageName(): only one version/state ' . - 'delimiter "-" is allowed in "' . $saveparam . '"', - 'version', null, null, $param); - } - list($param['package'], $param['version']) = $test; - } - } - // validation - $info = $this->channelExists($param['channel']); - if (PEAR::isError($info)) { - return $info; - } - if (!$info) { - return PEAR::raiseError('unknown channel "' . $param['channel'] . - '" in "' . $saveparam . '"', 'channel', null, null, $param); - } - $chan = $this->getChannel($param['channel']); - if (PEAR::isError($chan)) { - return $chan; - } - if (!$chan) { - return PEAR::raiseError("Exception: corrupt registry, could not " . - "retrieve channel " . $param['channel'] . " information", - 'registry', null, null, $param); - } - $param['channel'] = $chan->getName(); - $validate = $chan->getValidationObject(); - $vpackage = $chan->getValidationPackage(); - // validate package name - if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { - return PEAR::raiseError('parsePackageName(): invalid package name "' . - $param['package'] . '" in "' . $saveparam . '"', - 'package', null, null, $param); - } - if (isset($param['group'])) { - if (!PEAR_Validate::validGroupName($param['group'])) { - return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . - '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, - $param); - } - } - if (isset($param['state'])) { - if (!in_array(strtolower($param['state']), $validate->getValidStates())) { - return PEAR::raiseError('parsePackageName(): state "' . $param['state'] - . '" is not a valid state in "' . $saveparam . '"', - 'state', null, null, $param); - } - } - if (isset($param['version'])) { - if (isset($param['state'])) { - return PEAR::raiseError('parsePackageName(): cannot contain both ' . - 'a version and a stability (state) in "' . $saveparam . '"', - 'version/state', null, null, $param); - } - // check whether version is actually a state - if (in_array(strtolower($param['version']), $validate->getValidStates())) { - $param['state'] = strtolower($param['version']); - unset($param['version']); - } else { - if (!$validate->validVersion($param['version'])) { - return PEAR::raiseError('parsePackageName(): "' . $param['version'] . - '" is neither a valid version nor a valid state in "' . - $saveparam . '"', 'version/state', null, null, $param); - } - } - } - return $param; - } - - /** - * @param array - * @return string - */ - function parsedPackageNameToString($parsed, $brief = false) - { - if (is_string($parsed)) { - return $parsed; - } - if (is_object($parsed)) { - $p = $parsed; - $parsed = array( - 'package' => $p->getPackage(), - 'channel' => $p->getChannel(), - 'version' => $p->getVersion(), - ); - } - if (isset($parsed['uri'])) { - return $parsed['uri']; - } - if ($brief) { - if ($channel = $this->channelAlias($parsed['channel'])) { - return $channel . '/' . $parsed['package']; - } - } - $upass = ''; - if (isset($parsed['user'])) { - $upass = $parsed['user']; - if (isset($parsed['pass'])) { - $upass .= ':' . $parsed['pass']; - } - $upass = "$upass@"; - } - $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; - if (isset($parsed['version']) || isset($parsed['state'])) { - $ver = isset($parsed['version']) ? $parsed['version'] : ''; - $ver .= isset($parsed['state']) ? $parsed['state'] : ''; - $ret .= '-' . $ver; - } - if (isset($parsed['extension'])) { - $ret .= '.' . $parsed['extension']; - } - if (isset($parsed['opts'])) { - $ret .= '?'; - foreach ($parsed['opts'] as $name => $value) { - $parsed['opts'][$name] = "$name=$value"; - } - $ret .= implode('&', $parsed['opts']); - } - if (isset($parsed['group'])) { - $ret .= '#' . $parsed['group']; - } - return $ret; - } -}PEAR-1.9.0/PEAR/REST.php100664 764 764 36073 100664 7354 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: REST.php 286489 2009-07-29 05:59:08Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * For downloading xml files - */ -require_once 'PEAR.php'; -require_once 'PEAR/XMLParser.php'; - -/** - * Intelligently retrieve data, following hyperlinks if necessary, and re-directing - * as well - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_REST -{ - var $config; - var $_options; - - function PEAR_REST(&$config, $options = array()) - { - $this->config = &$config; - $this->_options = $options; - } - - /** - * Retrieve REST data, but always retrieve the local cache if it is available. - * - * This is useful for elements that should never change, such as information on a particular - * release - * @param string full URL to this resource - * @param array|false contents of the accept-encoding header - * @param boolean if true, xml will be returned as a string, otherwise, xml will be - * parsed using PEAR_XMLParser - * @return string|array - */ - function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) - { - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; - - if (file_exists($cachefile)) { - return unserialize(implode('', file($cachefile))); - } - - return $this->retrieveData($url, $accept, $forcestring, $channel); - } - - /** - * Retrieve a remote REST resource - * @param string full URL to this resource - * @param array|false contents of the accept-encoding header - * @param boolean if true, xml will be returned as a string, otherwise, xml will be - * parsed using PEAR_XMLParser - * @return string|array - */ - function retrieveData($url, $accept = false, $forcestring = false, $channel = false) - { - $cacheId = $this->getCacheId($url); - if ($ret = $this->useLocalCache($url, $cacheId)) { - return $ret; - } - - $file = $trieddownload = false; - if (!isset($this->_options['offline'])) { - $trieddownload = true; - $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel); - } - - if (PEAR::isError($file)) { - if ($file->getCode() !== -9276) { - return $file; - } - - $trieddownload = false; - $file = false; // use local copy if available on socket connect error - } - - if (!$file) { - $ret = $this->getCache($url); - if (!PEAR::isError($ret) && $trieddownload) { - // reset the age of the cache if the server says it was unmodified - $this->saveCache($url, $ret, null, true, $cacheId); - } - - return $ret; - } - - if (is_array($file)) { - $headers = $file[2]; - $lastmodified = $file[1]; - $content = $file[0]; - } else { - $headers = array(); - $lastmodified = false; - $content = $file; - } - - if ($forcestring) { - $this->saveCache($url, $content, $lastmodified, false, $cacheId); - return $content; - } - - if (isset($headers['content-type'])) { - switch ($headers['content-type']) { - case 'text/xml' : - case 'application/xml' : - case 'text/plain' : - if ($headers['content-type'] === 'text/plain') { - $check = substr($content, 0, 5); - if ($check !== 'parse($content); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . - $err->getMessage()); - } - $content = $parser->getData(); - case 'text/html' : - default : - // use it as a string - } - } else { - // assume XML - $parser = new PEAR_XMLParser; - $parser->parse($content); - $content = $parser->getData(); - } - - $this->saveCache($url, $content, $lastmodified, false, $cacheId); - return $content; - } - - function useLocalCache($url, $cacheid = null) - { - if ($cacheid === null) { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - if (!file_exists($cacheidfile)) { - return false; - } - - $cacheid = unserialize(implode('', file($cacheidfile))); - } - - $cachettl = $this->config->get('cache_ttl'); - // If cache is newer than $cachettl seconds, we use the cache! - if (time() - $cacheid['age'] < $cachettl) { - return $this->getCache($url); - } - - return false; - } - - function getCacheId($url) - { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - - if (!file_exists($cacheidfile)) { - return false; - } - - $ret = unserialize(implode('', file($cacheidfile))); - return $ret; - } - - function getCache($url) - { - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; - - if (!file_exists($cachefile)) { - return PEAR::raiseError('No cached content available for "' . $url . '"'); - } - - return unserialize(implode('', file($cachefile))); - } - - /** - * @param string full URL to REST resource - * @param string original contents of the REST resource - * @param array HTTP Last-Modified and ETag headers - * @param bool if true, then the cache id file should be regenerated to - * trigger a new time-to-live value - */ - function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) - { - $cachedir = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . md5($url); - $cacheidfile = $cachedir . 'rest.cacheid'; - $cachefile = $cachedir . 'rest.cachefile'; - - if ($cacheid === null && $nochange) { - $cacheid = unserialize(implode('', file($cacheidfile))); - } - - $fp = @fopen($cacheidfile, 'wb'); - if (!$fp) { - $cache_dir = $this->config->get('cache_dir'); - if (is_dir($cache_dir)) { - return false; - } - - System::mkdir(array('-p', $cache_dir)); - $fp = @fopen($cacheidfile, 'wb'); - if (!$fp) { - return false; - } - } - - if ($nochange) { - fwrite($fp, serialize(array( - 'age' => time(), - 'lastChange' => $cacheid['lastChange'], - )) - ); - - fclose($fp); - return true; - } - - fwrite($fp, serialize(array( - 'age' => time(), - 'lastChange' => $lastmodified, - )) - ); - - fclose($fp); - $fp = @fopen($cachefile, 'wb'); - if (!$fp) { - if (file_exists($cacheidfile)) { - @unlink($cacheidfile); - } - - return false; - } - - fwrite($fp, serialize($contents)); - fclose($fp); - return true; - } - - /** - * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory - * This is best used for small files - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param string $save_dir directory to save file in - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @return string|array Returns the contents of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. - * - * @access public - */ - function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false) - { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); - } - - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); - } - - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; - $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; - - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($this->config->get('http_proxy')&& - $proxy = parse_url($this->config->get('http_proxy')) - ) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if ($schema === 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } - - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - $proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http'; - } - - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; - } - - if (isset($proxy['host'])) { - $request = "GET $url HTTP/1.1\r\n"; - } else { - $request = "GET $path HTTP/1.1\r\n"; - } - - $request .= "Host: $host:$port\r\n"; - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; - } - - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; - } - } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); - } - - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; - - $username = $this->config->get('username', null, $channel); - $password = $this->config->get('password', null, $channel); - - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; - } - - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; - } - - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; - } - - $request .= "Accept-Encoding:\r\n"; - $request .= "Connection: close\r\n"; - $request .= "\r\n"; - - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); - if (!$fp) { - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276); - } - } else { - if ($schema === 'https') { - $host = 'ssl://' . $host; - } - - $fp = @fsockopen($host, $port, $errno, $errstr); - if (!$fp) { - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); - } - } - - fwrite($fp, $request); - - $headers = array(); - $reply = 0; - while ($line = trim(fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; - } - - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)"); - } - } - } - - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)"); - } - - if ($wasredirect > 4) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)"); - } - - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel); - } - - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - - $data = ''; - while ($chunk = @fread($fp, 8192)) { - $data .= $chunk; - } - fclose($fp); - - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); - } - - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; - } else { - $lastmodified = $headers['last-modified']; - } - } - - return array($data, $lastmodified, $headers); - } - - return $data; - } -}PEAR-1.9.0/PEAR/RunTest.php100664 764 764 105252 100664 10217 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: RunTest.php 287447 2009-08-18 11:46:19Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.3 - */ - -/** - * for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Config.php'; - -define('DETAILED', 1); -putenv("PHP_PEAR_RUNTESTS=1"); - -/** - * Simplified version of PHP's test suite - * - * Try it with: - * - * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);' - * - * - * @category pear - * @package PEAR - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.3 - */ -class PEAR_RunTest -{ - var $_headers = array(); - var $_logger; - var $_options; - var $_php; - var $tests_count; - var $xdebug_loaded; - /** - * Saved value of php executable, used to reset $_php when we - * have a test that uses cgi - * - * @var unknown_type - */ - var $_savephp; - var $ini_overwrites = array( - 'output_handler=', - 'open_basedir=', - 'safe_mode=0', - 'disable_functions=', - 'output_buffering=Off', - 'display_errors=1', - 'log_errors=0', - 'html_errors=0', - 'track_errors=1', - 'report_memleaks=0', - 'report_zend_debug=0', - 'docref_root=', - 'docref_ext=.html', - 'error_prepend_string=', - 'error_append_string=', - 'auto_prepend_file=', - 'auto_append_file=', - 'magic_quotes_runtime=0', - 'xdebug.default_enable=0', - 'allow_url_fopen=1', - ); - - /** - * An object that supports the PEAR_Common->log() signature, or null - * @param PEAR_Common|null - */ - function PEAR_RunTest($logger = null, $options = array()) - { - if (!defined('E_DEPRECATED')) { - define('E_DEPRECATED', 0); - } - if (!defined('E_STRICT')) { - define('E_STRICT', 0); - } - $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT)); - if (is_null($logger)) { - require_once 'PEAR/Common.php'; - $logger = new PEAR_Common; - } - $this->_logger = $logger; - $this->_options = $options; - - $conf = &PEAR_Config::singleton(); - $this->_php = $conf->get('php_bin'); - } - - /** - * Taken from php-src/run-tests.php - * - * @param string $commandline command name - * @param array $env - * @param string $stdin standard input to pass to the command - * @return unknown - */ - function system_with_timeout($commandline, $env = null, $stdin = null) - { - $data = ''; - if (version_compare(phpversion(), '5.0.0', '<')) { - $proc = proc_open($commandline, array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') - ), $pipes); - } else { - $proc = proc_open($commandline, array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') - ), $pipes, null, $env, array('suppress_errors' => true)); - } - - if (!$proc) { - return false; - } - - if (is_string($stdin)) { - fwrite($pipes[0], $stdin); - } - fclose($pipes[0]); - - while (true) { - /* hide errors from interrupted syscalls */ - $r = $pipes; - $e = $w = null; - $n = @stream_select($r, $w, $e, 60); - - if ($n === 0) { - /* timed out */ - $data .= "\n ** ERROR: process timed out **\n"; - proc_terminate($proc); - return array(1234567890, $data); - } else if ($n > 0) { - $line = fread($pipes[1], 8192); - if (strlen($line) == 0) { - /* EOF */ - break; - } - $data .= $line; - } - } - if (function_exists('proc_get_status')) { - $stat = proc_get_status($proc); - if ($stat['signaled']) { - $data .= "\nTermsig=".$stat['stopsig']; - } - } - $code = proc_close($proc); - if (function_exists('proc_get_status')) { - $code = $stat['exitcode']; - } - return array($code, $data); - } - - /** - * Turns a PHP INI string into an array - * - * Turns -d "include_path=/foo/bar" into this: - * array( - * 'include_path' => array( - * 'operator' => '-d', - * 'value' => '/foo/bar', - * ) - * ) - * Works both with quotes and without - * - * @param string an PHP INI string, -d "include_path=/foo/bar" - * @return array - */ - function iniString2array($ini_string) - { - if (!$ini_string) { - return array(); - } - $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY); - $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1]; - $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2]; - // FIXME review if this is really the struct to go with - $array = array($key => array('operator' => $split[0], 'value' => $value)); - return $array; - } - - function settings2array($settings, $ini_settings) - { - foreach ($settings as $setting) { - if (strpos($setting, '=') !== false) { - $setting = explode('=', $setting, 2); - $name = trim(strtolower($setting[0])); - $value = trim($setting[1]); - $ini_settings[$name] = $value; - } - } - return $ini_settings; - } - - function settings2params($ini_settings) - { - $settings = ''; - foreach ($ini_settings as $name => $value) { - if (is_array($value)) { - $operator = $value['operator']; - $value = $value['value']; - } else { - $operator = '-d'; - } - $value = addslashes($value); - $settings .= " $operator \"$name=$value\""; - } - return $settings; - } - - function _preparePhpBin($php, $file, $ini_settings) - { - $file = escapeshellarg($file); - // This was fixed in php 5.3 and is not needed after that - if (OS_WINDOWS && version_compare(PHP_VERSION, '5.3', '<')) { - $cmd = '"'.escapeshellarg($php).' '.$ini_settings.' -f ' . $file .'"'; - } else { - $cmd = $php . $ini_settings . ' -f ' . $file; - } - - return $cmd; - } - - function runPHPUnit($file, $ini_settings = '') - { - if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) { - $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file); - } elseif (file_exists($file)) { - $file = realpath($file); - } - - $cmd = $this->_preparePhpBin($this->_php, $file, $ini_settings); - if (isset($this->_logger)) { - $this->_logger->log(2, 'Running command "' . $cmd . '"'); - } - - $savedir = getcwd(); // in case the test moves us around - chdir(dirname($file)); - echo `$cmd`; - chdir($savedir); - return 'PASSED'; // we have no way of knowing this information so assume passing - } - - /** - * Runs an individual test case. - * - * @param string The filename of the test - * @param array|string INI settings to be applied to the test run - * @param integer Number what the current running test is of the - * whole test suite being runned. - * - * @return string|object Returns PASSED, WARNED, FAILED depending on how the - * test came out. - * PEAR Error when the tester it self fails - */ - function run($file, $ini_settings = array(), $test_number = 1) - { - if (isset($this->_savephp)) { - $this->_php = $this->_savephp; - unset($this->_savephp); - } - if (empty($this->_options['cgi'])) { - // try to see if php-cgi is in the path - $res = $this->system_with_timeout('php-cgi -v'); - if (false !== $res && !(is_array($res) && $res === array(127, ''))) { - $this->_options['cgi'] = 'php-cgi'; - } - } - if (1 < $len = strlen($this->tests_count)) { - $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT); - $test_nr = "[$test_number/$this->tests_count] "; - } else { - $test_nr = ''; - } - - $file = realpath($file); - $section_text = $this->_readFile($file); - if (PEAR::isError($section_text)) { - return $section_text; - } - - if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) { - return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file"); - } - - $cwd = getcwd(); - - $pass_options = ''; - if (!empty($this->_options['ini'])) { - $pass_options = $this->_options['ini']; - } - - if (is_string($ini_settings)) { - $ini_settings = $this->iniString2array($ini_settings); - } - - $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings); - if ($section_text['INI']) { - if (strpos($section_text['INI'], '{PWD}') !== false) { - $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); - } - $ini = preg_split( "/[\n\r]+/", $section_text['INI']); - $ini_settings = $this->settings2array($ini, $ini_settings); - } - $ini_settings = $this->settings2params($ini_settings); - $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file); - - $tested = trim($section_text['TEST']); - $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' '; - - if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) || - !empty($section_text['UPLOAD']) || !empty($section_text['GET']) || - !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { - if (empty($this->_options['cgi'])) { - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info'); - } - return 'SKIPPED'; - } - $this->_savephp = $this->_php; - $this->_php = $this->_options['cgi']; - } - - $temp_dir = realpath(dirname($file)); - $main_file_name = basename($file, 'phpt'); - $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff'; - $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log'; - $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp'; - $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out'; - $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem'; - $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; - $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; - $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; - $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); - - // unlink old test results - $this->_cleanupOldFiles($file); - - // Check if test should be skipped. - $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings); - if (count($res) != 2) { - return $res; - } - $info = $res['info']; - $warn = $res['warn']; - - // We've satisfied the preconditions - run the test! - if (isset($this->_options['coverage']) && $this->xdebug_loaded) { - $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug'; - $text = '"; - - $len_f = 5; - if (substr($section_text['FILE'], 0, 5) != 'save_text($temp_file, $text); - } else { - $this->save_text($temp_file, $section_text['FILE']); - } - - $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; - $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings); - $cmd.= "$args 2>&1"; - if (isset($this->_logger)) { - $this->_logger->log(2, 'Running command "' . $cmd . '"'); - } - - // Reset environment from any previous test. - $env = $this->_resetEnv($section_text, $temp_file); - - $section_text = $this->_processUpload($section_text, $file); - if (PEAR::isError($section_text)) { - return $section_text; - } - - if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { - $post = trim($section_text['POST_RAW']); - $raw_lines = explode("\n", $post); - - $request = ''; - $started = false; - foreach ($raw_lines as $i => $line) { - if (empty($env['CONTENT_TYPE']) && - preg_match('/^Content-Type:(.*)/i', $line, $res)) { - $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); - continue; - } - if ($started) { - $request .= "\n"; - } - $started = true; - $request .= $line; - } - - $env['CONTENT_LENGTH'] = strlen($request); - $env['REQUEST_METHOD'] = 'POST'; - - $this->save_text($tmp_post, $request); - $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; - } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { - $post = trim($section_text['POST']); - $this->save_text($tmp_post, $post); - $content_length = strlen($post); - - $env['REQUEST_METHOD'] = 'POST'; - $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - $env['CONTENT_LENGTH'] = $content_length; - - $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; - } else { - $env['REQUEST_METHOD'] = 'GET'; - $env['CONTENT_TYPE'] = ''; - $env['CONTENT_LENGTH'] = ''; - } - - if (OS_WINDOWS && isset($section_text['RETURNS'])) { - ob_start(); - system($cmd, $return_value); - $out = ob_get_contents(); - ob_end_clean(); - $section_text['RETURNS'] = (int) trim($section_text['RETURNS']); - $returnfail = ($return_value != $section_text['RETURNS']); - } else { - $returnfail = false; - $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null; - $out = $this->system_with_timeout($cmd, $env, $stdin); - $return_value = $out[0]; - $out = $out[1]; - } - - $output = preg_replace('/\r\n/', "\n", trim($out)); - - if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) { - @unlink(realpath($tmp_post)); - } - chdir($cwd); // in case the test moves us around - - $this->_testCleanup($section_text, $temp_clean); - - /* when using CGI, strip the headers from the output */ - $output = $this->_stripHeadersCGI($output); - - if (isset($section_text['EXPECTHEADERS'])) { - $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']); - $missing = array_diff_assoc($testheaders, $this->_headers); - $changed = ''; - foreach ($missing as $header => $value) { - if (isset($this->_headers[$header])) { - $changed .= "-$header: $value\n+$header: "; - $changed .= $this->_headers[$header]; - } else { - $changed .= "-$header: $value\n"; - } - } - if ($missing) { - // tack on failed headers to output: - $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed"; - } - } - // Does the output match what is expected? - do { - if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { - if (isset($section_text['EXPECTF'])) { - $wanted = trim($section_text['EXPECTF']); - } else { - $wanted = trim($section_text['EXPECTREGEX']); - } - $wanted_re = preg_replace('/\r\n/', "\n", $wanted); - if (isset($section_text['EXPECTF'])) { - $wanted_re = preg_quote($wanted_re, '/'); - // Stick to basics - $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy - $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re); - $wanted_re = str_replace("%d", "[0-9]+", $wanted_re); - $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re); - $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re); - $wanted_re = str_replace("%c", ".", $wanted_re); - // %f allows two points "-.0.0" but that is the best *simple* expression - } - - /* DEBUG YOUR REGEX HERE - var_dump($wanted_re); - print(str_repeat('=', 80) . "\n"); - var_dump($output); - */ - if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) { - if (file_exists($temp_file)) { - unlink($temp_file); - } - if (array_key_exists('FAIL', $section_text)) { - break; - } - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "PASS $test_nr$tested$info"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' - ' . $tested); - } - return 'PASSED'; - } - } else { - if (isset($section_text['EXPECTFILE'])) { - $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']); - if (!($fp = @fopen($f, 'rb'))) { - return PEAR::raiseError('--EXPECTFILE-- section file ' . - $f . ' not found'); - } - fclose($fp); - $section_text['EXPECT'] = file_get_contents($f); - } - - if (isset($section_text['EXPECT'])) { - $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT'])); - } else { - $wanted = ''; - } - - // compare and leave on success - if (!$returnfail && 0 == strcmp($output, $wanted)) { - if (file_exists($temp_file)) { - unlink($temp_file); - } - if (array_key_exists('FAIL', $section_text)) { - break; - } - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "PASS $test_nr$tested$info"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' - ' . $tested); - } - return 'PASSED'; - } - } - } while (false); - - if (array_key_exists('FAIL', $section_text)) { - // we expect a particular failure - // this is only used for testing PEAR_RunTest - $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; - $faildiff = $this->generate_diff($wanted, $output, null, $expectf); - $faildiff = preg_replace('/\r/', '', $faildiff); - $wanted = preg_replace('/\r/', '', trim($section_text['FAIL'])); - if ($faildiff == $wanted) { - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "PASS $test_nr$tested$info"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' - ' . $tested); - } - return 'PASSED'; - } - unset($section_text['EXPECTF']); - $output = $faildiff; - if (isset($section_text['RETURNS'])) { - return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' . - $file); - } - } - - // Test failed so we need to report details. - $txt = $warn ? 'WARN ' : 'FAIL '; - $this->_logger->log(0, $txt . $test_nr . $tested . $info); - - // write .exp - $res = $this->_writeLog($exp_filename, $wanted); - if (PEAR::isError($res)) { - return $res; - } - - // write .out - $res = $this->_writeLog($output_filename, $output); - if (PEAR::isError($res)) { - return $res; - } - - // write .diff - $returns = isset($section_text['RETURNS']) ? - array(trim($section_text['RETURNS']), $return_value) : null; - $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; - $data = $this->generate_diff($wanted, $output, $returns, $expectf); - $res = $this->_writeLog($diff_filename, $data); - if (PEAR::isError($res)) { - return $res; - } - - // write .log - $data = " ----- EXPECTED OUTPUT -$wanted ----- ACTUAL OUTPUT -$output ----- FAILED -"; - - if ($returnfail) { - $data .= " ----- EXPECTED RETURN -$section_text[RETURNS] ----- ACTUAL RETURN -$return_value -"; - } - - $res = $this->_writeLog($log_filename, $data); - if (PEAR::isError($res)) { - return $res; - } - - if (isset($this->_options['tapoutput'])) { - $wanted = explode("\n", $wanted); - $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted); - $output = explode("\n", $output); - $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output); - return array($wanted . $output . 'not ok', ' - ' . $tested); - } - return $warn ? 'WARNED' : 'FAILED'; - } - - function generate_diff($wanted, $output, $rvalue, $wanted_re) - { - $w = explode("\n", $wanted); - $o = explode("\n", $output); - $wr = explode("\n", $wanted_re); - $w1 = array_diff_assoc($w, $o); - $o1 = array_diff_assoc($o, $w); - $o2 = $w2 = array(); - foreach ($w1 as $idx => $val) { - if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) || - !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) { - $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val; - } - } - foreach ($o1 as $idx => $val) { - if (!$wanted_re || !isset($wr[$idx]) || - !preg_match('/^' . $wr[$idx] . '\\z/', $val)) { - $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val; - } - } - $diff = array_merge($w2, $o2); - ksort($diff); - $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : ''; - return implode("\r\n", $diff) . $extra; - } - - // Write the given text to a temporary file, and return the filename. - function save_text($filename, $text) - { - if (!$fp = fopen($filename, 'w')) { - return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)"); - } - fwrite($fp, $text); - fclose($fp); - if (1 < DETAILED) echo " -FILE $filename {{{ -$text -}}} -"; - } - - function _cleanupOldFiles($file) - { - $temp_dir = realpath(dirname($file)); - $mainFileName = basename($file, 'phpt'); - $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff'; - $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log'; - $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp'; - $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out'; - $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem'; - $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php'; - $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php'; - $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php'; - $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); - - // unlink old test results - @unlink($diff_filename); - @unlink($log_filename); - @unlink($exp_filename); - @unlink($output_filename); - @unlink($memcheck_filename); - @unlink($temp_file); - @unlink($temp_skipif); - @unlink($tmp_post); - @unlink($temp_clean); - } - - function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings) - { - $info = ''; - $warn = false; - if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) { - $this->save_text($temp_skipif, $section_text['SKIPIF']); - $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\""); - $output = $output[1]; - $loutput = ltrim($output); - unlink($temp_skipif); - if (!strncasecmp('skip', $loutput, 4)) { - $skipreason = "SKIP $tested"; - if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { - $skipreason .= '(reason: ' . $m[1] . ')'; - } - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, $skipreason); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' # skip ' . $reason); - } - return 'SKIPPED'; - } - - if (!strncasecmp('info', $loutput, 4) - && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { - $info = " (info: $m[1])"; - } - - if (!strncasecmp('warn', $loutput, 4) - && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { - $warn = true; /* only if there is a reason */ - $info = " (warn: $m[1])"; - } - } - - return array('warn' => $warn, 'info' => $info); - } - - function _stripHeadersCGI($output) - { - $this->headers = array(); - if (!empty($this->_options['cgi']) && - $this->_php == $this->_options['cgi'] && - preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) { - $output = isset($match[2]) ? trim($match[2]) : ''; - $this->_headers = $this->_processHeaders($match[1]); - } - - return $output; - } - - /** - * Return an array that can be used with array_diff() to compare headers - * - * @param string $text - */ - function _processHeaders($text) - { - $headers = array(); - $rh = preg_split("/[\n\r]+/", $text); - foreach ($rh as $line) { - if (strpos($line, ':')!== false) { - $line = explode(':', $line, 2); - $headers[trim($line[0])] = trim($line[1]); - } - } - return $headers; - } - - function _readFile($file) - { - // Load the sections of the test file. - $section_text = array( - 'TEST' => '(unnamed test)', - 'SKIPIF' => '', - 'GET' => '', - 'COOKIE' => '', - 'POST' => '', - 'ARGS' => '', - 'INI' => '', - 'CLEAN' => '', - ); - - if (!is_file($file) || !$fp = fopen($file, "r")) { - return PEAR::raiseError("Cannot open test file: $file"); - } - - $section = ''; - while (!feof($fp)) { - $line = fgets($fp); - - // Match the beginning of a section. - if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { - $section = $r[1]; - $section_text[$section] = ''; - continue; - } elseif (empty($section)) { - fclose($fp); - return PEAR::raiseError("Invalid sections formats in test file: $file"); - } - - // Add to the section text. - $section_text[$section] .= $line; - } - fclose($fp); - - return $section_text; - } - - function _writeLog($logname, $data) - { - if (!$log = fopen($logname, 'w')) { - return PEAR::raiseError("Cannot create test log - $logname"); - } - fwrite($log, $data); - fclose($log); - } - - function _resetEnv($section_text, $temp_file) - { - $env = $_ENV; - $env['REDIRECT_STATUS'] = ''; - $env['QUERY_STRING'] = ''; - $env['PATH_TRANSLATED'] = ''; - $env['SCRIPT_FILENAME'] = ''; - $env['REQUEST_METHOD'] = ''; - $env['CONTENT_TYPE'] = ''; - $env['CONTENT_LENGTH'] = ''; - if (!empty($section_text['ENV'])) { - if (strpos($section_text['ENV'], '{PWD}') !== false) { - $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']); - } - foreach (explode("\n", trim($section_text['ENV'])) as $e) { - $e = explode('=', trim($e), 2); - if (!empty($e[0]) && isset($e[1])) { - $env[$e[0]] = $e[1]; - } - } - } - if (array_key_exists('GET', $section_text)) { - $env['QUERY_STRING'] = trim($section_text['GET']); - } else { - $env['QUERY_STRING'] = ''; - } - if (array_key_exists('COOKIE', $section_text)) { - $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); - } else { - $env['HTTP_COOKIE'] = ''; - } - $env['REDIRECT_STATUS'] = '1'; - $env['PATH_TRANSLATED'] = $temp_file; - $env['SCRIPT_FILENAME'] = $temp_file; - - return $env; - } - - function _processUpload($section_text, $file) - { - if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) { - $upload_files = trim($section_text['UPLOAD']); - $upload_files = explode("\n", $upload_files); - - $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" . - "-----------------------------20896060251896012921717172737\n"; - foreach ($upload_files as $fileinfo) { - $fileinfo = explode('=', $fileinfo); - if (count($fileinfo) != 2) { - return PEAR::raiseError("Invalid UPLOAD section in test file: $file"); - } - if (!realpath(dirname($file) . '/' . $fileinfo[1])) { - return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " . - "in test file: $file"); - } - $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]); - $fileinfo[1] = basename($fileinfo[1]); - $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n"; - $request .= "Content-Type: text/plain\n\n"; - $request .= $file_contents . "\n" . - "-----------------------------20896060251896012921717172737\n"; - } - - if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { - // encode POST raw - $post = trim($section_text['POST']); - $post = explode('&', $post); - foreach ($post as $i => $post_info) { - $post_info = explode('=', $post_info); - if (count($post_info) != 2) { - return PEAR::raiseError("Invalid POST data in test file: $file"); - } - $post_info[0] = rawurldecode($post_info[0]); - $post_info[1] = rawurldecode($post_info[1]); - $post[$i] = $post_info; - } - foreach ($post as $post_info) { - $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n"; - $request .= $post_info[1] . "\n" . - "-----------------------------20896060251896012921717172737\n"; - } - unset($section_text['POST']); - } - $section_text['POST_RAW'] = $request; - } - - return $section_text; - } - - function _testCleanup($section_text, $temp_clean) - { - if ($section_text['CLEAN']) { - // perform test cleanup - $this->save_text($temp_clean, $section_text['CLEAN']); - $output = $this->system_with_timeout("$this->_php $temp_clean 2>&1"); - if (strlen($output[1])) { - echo "BORKED --CLEAN-- section! output:\n", $output[1]; - } - if (file_exists($temp_clean)) { - unlink($temp_clean); - } - } - } -}PEAR-1.9.0/PEAR/Validate.php100664 764 764 53055 100664 10327 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validate.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/**#@+ - * Constants for install stage - */ -define('PEAR_VALIDATE_INSTALLING', 1); -define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others -define('PEAR_VALIDATE_NORMAL', 3); -define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others -define('PEAR_VALIDATE_PACKAGING', 7); -/**#@-*/ -require_once 'PEAR/Common.php'; -require_once 'PEAR/Validator/PECL.php'; - -/** - * Validation class for package.xml - channel-level advanced validation - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Validate -{ - var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG; - /** - * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - var $_packagexml; - /** - * @var int one of the PEAR_VALIDATE_* constants - */ - var $_state = PEAR_VALIDATE_NORMAL; - /** - * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same) - * @var array - * @access private - */ - var $_failures = array('error' => array(), 'warning' => array()); - - /** - * Override this method to handle validation of normal package names - * @param string - * @return bool - * @access protected - */ - function _validPackageName($name) - { - return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name); - } - - /** - * @param string package name to validate - * @param string name of channel-specific validation package - * @final - */ - function validPackageName($name, $validatepackagename = false) - { - if ($validatepackagename) { - if (strtolower($name) == strtolower($validatepackagename)) { - return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name); - } - } - return $this->_validPackageName($name); - } - - /** - * This validates a bundle name, and bundle names must conform - * to the PEAR naming convention, so the method is final and static. - * @param string - * @final - * @static - */ - function validGroupName($name) - { - return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name); - } - - /** - * Determine whether $state represents a valid stability level - * @param string - * @return bool - * @static - * @final - */ - function validState($state) - { - return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable')); - } - - /** - * Get a list of valid stability levels - * @return array - * @static - * @final - */ - function getValidStates() - { - return array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - } - - /** - * Determine whether a version is a properly formatted version number that can be used - * by version_compare - * @param string - * @return bool - * @static - * @final - */ - function validVersion($ver) - { - return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function setPackageFile(&$pf) - { - $this->_packagexml = &$pf; - } - - /** - * @access private - */ - function _addFailure($field, $reason) - { - $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason); - } - - /** - * @access private - */ - function _addWarning($field, $reason) - { - $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason); - } - - function getFailures() - { - $failures = $this->_failures; - $this->_failures = array('warnings' => array(), 'errors' => array()); - return $failures; - } - - /** - * @param int one of the PEAR_VALIDATE_* constants - */ - function validate($state = null) - { - if (!isset($this->_packagexml)) { - return false; - } - if ($state !== null) { - $this->_state = $state; - } - $this->_failures = array('warnings' => array(), 'errors' => array()); - $this->validatePackageName(); - $this->validateVersion(); - $this->validateMaintainers(); - $this->validateDate(); - $this->validateSummary(); - $this->validateDescription(); - $this->validateLicense(); - $this->validateNotes(); - if ($this->_packagexml->getPackagexmlVersion() == '1.0') { - $this->validateState(); - $this->validateFilelist(); - } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' || - $this->_packagexml->getPackagexmlVersion() == '2.1') { - $this->validateTime(); - $this->validateStability(); - $this->validateDeps(); - $this->validateMainFilelist(); - $this->validateReleaseFilelist(); - //$this->validateGlobalTasks(); - $this->validateChangelog(); - } - return !((bool) count($this->_failures['errors'])); - } - - /** - * @access protected - */ - function validatePackageName() - { - if ($this->_state == PEAR_VALIDATE_PACKAGING || - $this->_state == PEAR_VALIDATE_NORMAL) { - if (($this->_packagexml->getPackagexmlVersion() == '2.0' || - $this->_packagexml->getPackagexmlVersion() == '2.1') && - $this->_packagexml->getExtends()) { - $version = $this->_packagexml->getVersion() . ''; - $name = $this->_packagexml->getPackage(); - $test = array_shift($a = explode('.', $version)); - if ($test == '0') { - return true; - } - $vlen = strlen($test); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if ($majver != $test) { - $this->_addWarning('package', "package $name extends package " . - $this->_packagexml->getExtends() . ' and so the name should ' . - 'have a postfix equal to the major version like "' . - $this->_packagexml->getExtends() . $test . '"'); - return true; - } elseif (substr($name, 0, strlen($name) - $vlen) != - $this->_packagexml->getExtends()) { - $this->_addWarning('package', "package $name extends package " . - $this->_packagexml->getExtends() . ' and so the name must ' . - 'be an extension like "' . $this->_packagexml->getExtends() . - $test . '"'); - return true; - } - } - } - if (!$this->validPackageName($this->_packagexml->getPackage())) { - $this->_addFailure('name', 'package name "' . - $this->_packagexml->getPackage() . '" is invalid'); - return false; - } - } - - /** - * @access protected - */ - function validateVersion() - { - if ($this->_state != PEAR_VALIDATE_PACKAGING) { - if (!$this->validVersion($this->_packagexml->getVersion())) { - $this->_addFailure('version', - 'Invalid version number "' . $this->_packagexml->getVersion() . '"'); - } - return false; - } - $version = $this->_packagexml->getVersion(); - $versioncomponents = explode('.', $version); - if (count($versioncomponents) != 3) { - $this->_addWarning('version', - 'A version number should have 3 decimals (x.y.z)'); - return true; - } - $name = $this->_packagexml->getPackage(); - // version must be based upon state - switch ($this->_packagexml->getState()) { - case 'snapshot' : - return true; - case 'devel' : - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } else { - $this->_addWarning('version', - 'packages with devel stability must be < version 1.0.0'); - } - return true; - break; - case 'alpha' : - case 'beta' : - // check for a package that extends a package, - // like Foo and Foo2 - if ($this->_state == PEAR_VALIDATE_PACKAGING) { - if (substr($versioncomponents[2], 1, 2) == 'rc') { - $this->_addFailure('version', 'Release Candidate versions ' . - 'must have capital RC, not lower-case rc'); - return false; - } - } - if (!$this->_packagexml->getExtends()) { - if ($versioncomponents[0] == '1') { - if ($versioncomponents[2]{0} == '0') { - if ($versioncomponents[2] == '0') { - // version 1.*.0000 - $this->_addWarning('version', - 'version 1.' . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return true; - } elseif (strlen($versioncomponents[2]) > 1) { - // version 1.*.0RC1 or 1.*.0beta24 etc. - return true; - } else { - // version 1.*.0 - $this->_addWarning('version', - 'version 1.' . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return true; - } - } else { - $this->_addWarning('version', - 'bugfix versions (1.3.x where x > 0) probably should ' . - 'not be alpha or beta'); - return true; - } - } elseif ($versioncomponents[0] != '0') { - $this->_addWarning('version', - 'major versions greater than 1 are not allowed for packages ' . - 'without an tag or an identical postfix (foo2 v2.0.0)'); - return true; - } - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } - } else { - $vlen = strlen($versioncomponents[0] . ''); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { - $this->_addWarning('version', 'first version number "' . - $versioncomponents[0] . '" must match the postfix of ' . - 'package name "' . $name . '" (' . - $majver . ')'); - return true; - } - if ($versioncomponents[0] == $majver) { - if ($versioncomponents[2]{0} == '0') { - if ($versioncomponents[2] == '0') { - // version 2.*.0000 - $this->_addWarning('version', - "version $majver." . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return false; - } elseif (strlen($versioncomponents[2]) > 1) { - // version 2.*.0RC1 or 2.*.0beta24 etc. - return true; - } else { - // version 2.*.0 - $this->_addWarning('version', - "version $majver." . $versioncomponents[1] . - '.0 cannot be alpha or beta'); - return true; - } - } else { - $this->_addWarning('version', - "bugfix versions ($majver.x.y where y > 0) should " . - 'not be alpha or beta'); - return true; - } - } elseif ($versioncomponents[0] != '0') { - $this->_addWarning('version', - "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases"); - return true; - } - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } - } - return true; - break; - case 'stable' : - if ($versioncomponents[0] == '0') { - $this->_addWarning('version', 'versions less than 1.0.0 cannot ' . - 'be stable'); - return true; - } - if (!is_numeric($versioncomponents[2])) { - if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i', - $versioncomponents[2])) { - $this->_addWarning('version', 'version "' . $version . '" or any ' . - 'RC/beta/alpha version cannot be stable'); - return true; - } - } - // check for a package that extends a package, - // like Foo and Foo2 - if ($this->_packagexml->getExtends()) { - $vlen = strlen($versioncomponents[0] . ''); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { - $this->_addWarning('version', 'first version number "' . - $versioncomponents[0] . '" must match the postfix of ' . - 'package name "' . $name . '" (' . - $majver . ')'); - return true; - } - } elseif ($versioncomponents[0] > 1) { - $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' . - '1 for any package that does not have an tag'); - } - return true; - break; - default : - return false; - break; - } - } - - /** - * @access protected - */ - function validateMaintainers() - { - // maintainers can only be truly validated server-side for most channels - // but allow this customization for those who wish it - return true; - } - - /** - * @access protected - */ - function validateDate() - { - if ($this->_state == PEAR_VALIDATE_NORMAL || - $this->_state == PEAR_VALIDATE_PACKAGING) { - - if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/', - $this->_packagexml->getDate(), $res) || - count($res) < 4 - || !checkdate($res[2], $res[3], $res[1]) - ) { - $this->_addFailure('date', 'invalid release date "' . - $this->_packagexml->getDate() . '"'); - return false; - } - - if ($this->_state == PEAR_VALIDATE_PACKAGING && - $this->_packagexml->getDate() != date('Y-m-d')) { - $this->_addWarning('date', 'Release Date "' . - $this->_packagexml->getDate() . '" is not today'); - } - } - return true; - } - - /** - * @access protected - */ - function validateTime() - { - if (!$this->_packagexml->getTime()) { - // default of no time value set - return true; - } - - // packager automatically sets time, so only validate if pear validate is called - if ($this->_state = PEAR_VALIDATE_NORMAL) { - if (!preg_match('/\d\d:\d\d:\d\d/', - $this->_packagexml->getTime())) { - $this->_addFailure('time', 'invalid release time "' . - $this->_packagexml->getTime() . '"'); - return false; - } - - $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches); - if ($result === false || empty($matches)) { - $this->_addFailure('time', 'invalid release time "' . - $this->_packagexml->getTime() . '"'); - return false; - } - } - - return true; - } - - /** - * @access protected - */ - function validateState() - { - // this is the closest to "final" php4 can get - if (!PEAR_Validate::validState($this->_packagexml->getState())) { - if (strtolower($this->_packagexml->getState() == 'rc')) { - $this->_addFailure('state', 'RC is not a state, it is a version ' . - 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta'); - } - $this->_addFailure('state', 'invalid release state "' . - $this->_packagexml->getState() . '", must be one of: ' . - implode(', ', PEAR_Validate::getValidStates())); - return false; - } - return true; - } - - /** - * @access protected - */ - function validateStability() - { - $ret = true; - $packagestability = $this->_packagexml->getState(); - $apistability = $this->_packagexml->getState('api'); - if (!PEAR_Validate::validState($packagestability)) { - $this->_addFailure('state', 'invalid release stability "' . - $this->_packagexml->getState() . '", must be one of: ' . - implode(', ', PEAR_Validate::getValidStates())); - $ret = false; - } - $apistates = PEAR_Validate::getValidStates(); - array_shift($apistates); // snapshot is not allowed - if (!in_array($apistability, $apistates)) { - $this->_addFailure('state', 'invalid API stability "' . - $this->_packagexml->getState('api') . '", must be one of: ' . - implode(', ', $apistates)); - $ret = false; - } - return $ret; - } - - /** - * @access protected - */ - function validateSummary() - { - return true; - } - - /** - * @access protected - */ - function validateDescription() - { - return true; - } - - /** - * @access protected - */ - function validateLicense() - { - return true; - } - - /** - * @access protected - */ - function validateNotes() - { - return true; - } - - /** - * for package.xml 2.0 only - channels can't use package.xml 1.0 - * @access protected - */ - function validateDependencies() - { - return true; - } - - /** - * for package.xml 1.0 only - * @access private - */ - function _validateFilelist() - { - return true; // placeholder for now - } - - /** - * for package.xml 2.0 only - * @access protected - */ - function validateMainFilelist() - { - return true; // placeholder for now - } - - /** - * for package.xml 2.0 only - * @access protected - */ - function validateReleaseFilelist() - { - return true; // placeholder for now - } - - /** - * @access protected - */ - function validateChangelog() - { - return true; - } - - /** - * @access protected - */ - function validateFilelist() - { - return true; - } - - /** - * @access protected - */ - function validateDeps() - { - return true; - } -}PEAR-1.9.0/PEAR/XMLParser.php100664 764 764 16001 100664 10401 - * @author Stephan Schmidt (original XML_Unserializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: XMLParser.php 282970 2009-06-28 23:10:07Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Parser for any xml file - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stephan Schmidt (original XML_Unserializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_XMLParser -{ - /** - * unserilialized data - * @var string $_serializedData - */ - var $_unserializedData = null; - - /** - * name of the root tag - * @var string $_root - */ - var $_root = null; - - /** - * stack for all data that is found - * @var array $_dataStack - */ - var $_dataStack = array(); - - /** - * stack for all values that are generated - * @var array $_valStack - */ - var $_valStack = array(); - - /** - * current tag depth - * @var int $_depth - */ - var $_depth = 0; - - /** - * The XML encoding to use - * @var string $encoding - */ - var $encoding = 'ISO-8859-1'; - - /** - * @return array - */ - function getData() - { - return $this->_unserializedData; - } - - /** - * @param string xml content - * @return true|PEAR_Error - */ - function parse($data) - { - if (!extension_loaded('xml')) { - include_once 'PEAR.php'; - return PEAR::raiseError("XML Extension not found", 1); - } - $this->_dataStack = $this->_valStack = array(); - $this->_depth = 0; - - if ( - strpos($data, 'encoding="UTF-8"') - || strpos($data, 'encoding="utf-8"') - || strpos($data, "encoding='UTF-8'") - || strpos($data, "encoding='utf-8'") - ) { - $this->encoding = 'UTF-8'; - } - - if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') { - $data = utf8_decode($data); - $this->encoding = 'ISO-8859-1'; - } - - $xp = xml_parser_create($this->encoding); - xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0); - xml_set_object($xp, $this); - xml_set_element_handler($xp, 'startHandler', 'endHandler'); - xml_set_character_data_handler($xp, 'cdataHandler'); - if (!xml_parse($xp, $data)) { - $msg = xml_error_string(xml_get_error_code($xp)); - $line = xml_get_current_line_number($xp); - xml_parser_free($xp); - include_once 'PEAR.php'; - return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2); - } - xml_parser_free($xp); - return true; - } - - /** - * Start element handler for XML parser - * - * @access private - * @param object $parser XML parser object - * @param string $element XML element - * @param array $attribs attributes of XML tag - * @return void - */ - function startHandler($parser, $element, $attribs) - { - $this->_depth++; - $this->_dataStack[$this->_depth] = null; - - $val = array( - 'name' => $element, - 'value' => null, - 'type' => 'string', - 'childrenKeys' => array(), - 'aggregKeys' => array() - ); - - if (count($attribs) > 0) { - $val['children'] = array(); - $val['type'] = 'array'; - $val['children']['attribs'] = $attribs; - } - - array_push($this->_valStack, $val); - } - - /** - * post-process data - * - * @param string $data - * @param string $element element name - */ - function postProcess($data, $element) - { - return trim($data); - } - - /** - * End element handler for XML parser - * - * @access private - * @param object XML parser object - * @param string - * @return void - */ - function endHandler($parser, $element) - { - $value = array_pop($this->_valStack); - $data = $this->postProcess($this->_dataStack[$this->_depth], $element); - - // adjust type of the value - switch (strtolower($value['type'])) { - // unserialize an array - case 'array': - if ($data !== '') { - $value['children']['_content'] = $data; - } - - $value['value'] = isset($value['children']) ? $value['children'] : array(); - break; - - /* - * unserialize a null value - */ - case 'null': - $data = null; - break; - - /* - * unserialize any scalar value - */ - default: - settype($data, $value['type']); - $value['value'] = $data; - break; - } - - $parent = array_pop($this->_valStack); - if ($parent === null) { - $this->_unserializedData = &$value['value']; - $this->_root = &$value['name']; - return true; - } - - // parent has to be an array - if (!isset($parent['children']) || !is_array($parent['children'])) { - $parent['children'] = array(); - if ($parent['type'] != 'array') { - $parent['type'] = 'array'; - } - } - - if (!empty($value['name'])) { - // there already has been a tag with this name - if (in_array($value['name'], $parent['childrenKeys'])) { - // no aggregate has been created for this tag - if (!in_array($value['name'], $parent['aggregKeys'])) { - if (isset($parent['children'][$value['name']])) { - $parent['children'][$value['name']] = array($parent['children'][$value['name']]); - } else { - $parent['children'][$value['name']] = array(); - } - array_push($parent['aggregKeys'], $value['name']); - } - array_push($parent['children'][$value['name']], $value['value']); - } else { - $parent['children'][$value['name']] = &$value['value']; - array_push($parent['childrenKeys'], $value['name']); - } - } else { - array_push($parent['children'],$value['value']); - } - array_push($this->_valStack, $parent); - - $this->_depth--; - } - - /** - * Handler for character data - * - * @access private - * @param object XML parser object - * @param string CDATA - * @return void - */ - function cdataHandler($parser, $cdata) - { - $this->_dataStack[$this->_depth] .= $cdata; - } -}PEAR-1.9.0/scripts/pear.bat100775 764 764 11102 100775 10435 @ECHO OFF - -REM ---------------------------------------------------------------------- -REM PHP version 5 -REM ---------------------------------------------------------------------- -REM Copyright (c) 1997-2004 The PHP Group -REM ---------------------------------------------------------------------- -REM This source file is subject to version 3.0 of the PHP license, -REM that is bundled with this package in the file LICENSE, and is -REM available at through the world-wide-web at -REM http://www.php.net/license/3_0.txt. -REM If you did not receive a copy of the PHP license and are unable to -REM obtain it through the world-wide-web, please send a note to -REM license@php.net so we can mail you a copy immediately. -REM ---------------------------------------------------------------------- -REM Authors: Alexander Merz (alexmerz@php.net) -REM ---------------------------------------------------------------------- -REM -REM Last updated 12/29/2004 ($Id$ is not replaced if the file is binary) - -REM change this lines to match the paths of your system -REM ------------------- - - -REM Test to see if this is a raw pear.bat (uninstalled version) -SET TMPTMPTMPTMPT=@includ -SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ -FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) - -REM Check PEAR global ENV, set them if they do not exist -IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" -IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" -IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" -GOTO :INSTALLED - -:NOTINSTALLED -ECHO WARNING: This is a raw, uninstalled pear.bat - -REM Check to see if we can grab the directory of this file (Windows NT+) -IF %~n0 == pear ( -FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( -SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" -echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" -"%PHP_PEAR_PHP_BIN%" -v -GOTO :NEXTTEST -)) -GOTO :FAILAUTODETECT -:NEXTTEST -IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( - -REM We can use this PHP to run a temporary php file to get the dirname of pear - -echo ^ > ~~getloc.php -"%PHP_PEAR_PHP_BIN%" ~~getloc.php -set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a -DEL ~a.a -DEL ~~getloc.php -set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" - -REM Make sure there is a pearcmd.php at our disposal - -IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( -IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -) -) -GOTO :INSTALLED -) ELSE ( -REM Windows Me/98 cannot succeed, so allow the batch to fail -) -:FAILAUTODETECT -echo WARNING: failed to auto-detect pear information -:INSTALLED - -REM Check Folders and files -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 -IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR -IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR -REM launch pearcmd -GOTO RUN -:PEAR_INSTALL_ERROR -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_INSTALL_ERROR2 -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO pearcmd.php could not be found there. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_BIN_ERROR -ECHO PHP_PEAR_BIN_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_BIN_DIR% -GOTO END -:PEAR_PHPBIN_ERROR -ECHO PHP_PEAR_PHP_BIN is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_PHP_BIN% -GOTO END -:RUN -"%PHP_PEAR_PHP_BIN%" -C -d output_buffering=1 -d safe_mode=0 -d open_basedir="" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d register_argc_argv="On" -d "include_path='%PHP_PEAR_INSTALL_DIR%'" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 -:END -@ECHO ONPEAR-1.9.0/scripts/peardev.bat100664 764 764 11112 100664 11127 @ECHO OFF - -REM ---------------------------------------------------------------------- -REM PHP version 5 -REM ---------------------------------------------------------------------- -REM Copyright (c) 1997-2004 The PHP Group -REM ---------------------------------------------------------------------- -REM This source file is subject to version 3.0 of the PHP license, -REM that is bundled with this package in the file LICENSE, and is -REM available at through the world-wide-web at -REM http://www.php.net/license/3_0.txt. -REM If you did not receive a copy of the PHP license and are unable to -REM obtain it through the world-wide-web, please send a note to -REM license@php.net so we can mail you a copy immediately. -REM ---------------------------------------------------------------------- -REM Authors: Alexander Merz (alexmerz@php.net) -REM ---------------------------------------------------------------------- -REM -REM $Id: peardev.bat,v 1.6 2007-09-03 03:00:17 cellog Exp $ - -REM change this lines to match the paths of your system -REM ------------------- - - -REM Test to see if this is a raw pear.bat (uninstalled version) -SET TMPTMPTMPTMPT=@includ -SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ -FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) - -REM Check PEAR global ENV, set them if they do not exist -IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" -IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" -IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" -GOTO :INSTALLED - -:NOTINSTALLED -ECHO WARNING: This is a raw, uninstalled pear.bat - -REM Check to see if we can grab the directory of this file (Windows NT+) -IF %~n0 == pear ( -FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( -SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" -echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" -"%PHP_PEAR_PHP_BIN%" -v -GOTO :NEXTTEST -)) -GOTO :FAILAUTODETECT -:NEXTTEST -IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( - -REM We can use this PHP to run a temporary php file to get the dirname of pear - -echo ^ > ~~getloc.php -"%PHP_PEAR_PHP_BIN%" ~~getloc.php -set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a -DEL ~a.a -DEL ~~getloc.php -set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" - -REM Make sure there is a pearcmd.php at our disposal - -IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( -IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -) -) -GOTO :INSTALLED -) ELSE ( -REM Windows Me/98 cannot succeed, so allow the batch to fail -) -:FAILAUTODETECT -echo WARNING: failed to auto-detect pear information -:INSTALLED - -REM Check Folders and files -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 -IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR -IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR -REM launch pearcmd -GOTO RUN -:PEAR_INSTALL_ERROR -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_INSTALL_ERROR2 -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO pearcmd.php could not be found there. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_BIN_ERROR -ECHO PHP_PEAR_BIN_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_BIN_DIR% -GOTO END -:PEAR_PHPBIN_ERROR -ECHO PHP_PEAR_PHP_BIN is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_PHP_BIN% -GOTO END -:RUN -"%PHP_PEAR_PHP_BIN%" -C -d memory_limit="-1" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d open_basedir="" -d output_buffering=1 -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 -:END -@ECHO ONPEAR-1.9.0/scripts/pecl.bat100664 764 764 11003 100664 10423 @ECHO OFF - -REM ---------------------------------------------------------------------- -REM PHP version 5 -REM ---------------------------------------------------------------------- -REM Copyright (c) 1997-2004 The PHP Group -REM ---------------------------------------------------------------------- -REM This source file is subject to version 3.0 of the PHP license, -REM that is bundled with this package in the file LICENSE, and is -REM available at through the world-wide-web at -REM http://www.php.net/license/3_0.txt. -REM If you did not receive a copy of the PHP license and are unable to -REM obtain it through the world-wide-web, please send a note to -REM license@php.net so we can mail you a copy immediately. -REM ---------------------------------------------------------------------- -REM Authors: Alexander Merz (alexmerz@php.net) -REM ---------------------------------------------------------------------- -REM -REM Last updated 02/08/2004 ($Id$ is not replaced if the file is binary) - -REM change this lines to match the paths of your system -REM ------------------- - - -REM Test to see if this is a raw pear.bat (uninstalled version) -SET TMPTMPTMPTMPT=@includ -SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ -FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) - -REM Check PEAR global ENV, set them if they do not exist -IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" -IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" -IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" -GOTO :INSTALLED - -:NOTINSTALLED -ECHO WARNING: This is a raw, uninstalled pear.bat - -REM Check to see if we can grab the directory of this file (Windows NT+) -IF %~n0 == pear ( -FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( -SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" -echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" -"%PHP_PEAR_PHP_BIN%" -v -GOTO :NEXTTEST -)) -GOTO :FAILAUTODETECT -:NEXTTEST -IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( - -REM We can use this PHP to run a temporary php file to get the dirname of pear - -echo ^ > ~~getloc.php -"%PHP_PEAR_PHP_BIN%" ~~getloc.php -set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a -DEL ~a.a -DEL ~~getloc.php -set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" - -REM Make sure there is a pearcmd.php at our disposal - -IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( -IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -) -) -GOTO :INSTALLED -) ELSE ( -REM Windows Me/98 cannot succeed, so allow the batch to fail -) -:FAILAUTODETECT -echo WARNING: failed to auto-detect pear information -:INSTALLED - -REM Check Folders and files -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 -IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR -IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR -REM launch pearcmd -GOTO RUN -:PEAR_INSTALL_ERROR -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_INSTALL_ERROR2 -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO pearcmd.php could not be found there. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_BIN_ERROR -ECHO PHP_PEAR_BIN_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_BIN_DIR% -GOTO END -:PEAR_PHPBIN_ERROR -ECHO PHP_PEAR_PHP_BIN is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_PHP_BIN% -GOTO END -:RUN -"%PHP_PEAR_PHP_BIN%" -C -n -d output_buffering=1 -d safe_mode=0 -d include_path="%PHP_PEAR_INSTALL_DIR%" -d register_argc_argv="On" -d variables_order=EGPCS -f "%PHP_PEAR_INSTALL_DIR%\peclcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 -:END -@ECHO ONPEAR-1.9.0/scripts/pear.sh100664 764 764 1362 100664 10262 #!/bin/sh - -# first find which PHP binary to use -if test "x$PHP_PEAR_PHP_BIN" != "x"; then - PHP="$PHP_PEAR_PHP_BIN" -else - if test "@php_bin@" = '@'php_bin'@'; then - PHP=php - else - PHP="@php_bin@" - fi -fi - -# then look for the right pear include dir -if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then - INCDIR=$PHP_PEAR_INSTALL_DIR - INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" -else - if test "@php_dir@" = '@'php_dir'@'; then - INCDIR=`dirname $0` - INCARG="" - else - INCDIR="@php_dir@" - INCARG="-d include_path=@php_dir@" - fi -fi - -exec $PHP -C -q $INCARG -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@" -PEAR-1.9.0/scripts/peardev.sh100664 764 764 1407 100664 10761 #!/bin/sh - -# first find which PHP binary to use -if test "x$PHP_PEAR_PHP_BIN" != "x"; then - PHP="$PHP_PEAR_PHP_BIN" -else - if test "@php_bin@" = '@'php_bin'@'; then - PHP=php - else - PHP="@php_bin@" - fi -fi - -# then look for the right pear include dir -if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then - INCDIR=$PHP_PEAR_INSTALL_DIR - INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" -else - if test "@php_dir@" = '@'php_dir'@'; then - INCDIR=`dirname $0` - INCARG="" - else - INCDIR="@php_dir@" - INCARG="-d include_path=@php_dir@" - fi -fi - -exec $PHP -d memory_limit="-1" -C -q $INCARG -d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d variables_order=EGPCS -d auto_append_file="" $INCDIR/pearcmd.php "$@" -PEAR-1.9.0/scripts/pecl.sh100664 764 764 1263 100664 10256 #!/bin/sh - -# first find which PHP binary to use -if test "x$PHP_PEAR_PHP_BIN" != "x"; then - PHP="$PHP_PEAR_PHP_BIN" -else - if test "@php_bin@" = '@'php_bin'@'; then - PHP=php - else - PHP="@php_bin@" - fi -fi - -# then look for the right pear include dir -if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then - INCDIR=$PHP_PEAR_INSTALL_DIR - INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" -else - if test "@php_dir@" = '@'php_dir'@'; then - INCDIR=`dirname $0` - INCARG="" - else - INCDIR="@php_dir@" - INCARG="-d include_path=@php_dir@" - fi -fi - -exec $PHP -C -n -q $INCARG -d output_buffering=1 -d variables_order=EGPCS -d safe_mode=0 -d register_argc_argv="On" $INCDIR/peclcmd.php "$@" -PEAR-1.9.0/scripts/pearcmd.php100664 764 764 34076 100664 11153 - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: pearcmd.php 286487 2009-07-29 05:57:28Z dufuz $ - * @link http://pear.php.net/package/PEAR - */ - -ob_end_clean(); -if (!defined('PEAR_RUNTYPE')) { - // this is defined in peclcmd.php as 'pecl' - define('PEAR_RUNTYPE', 'pear'); -} -define('PEAR_IGNORE_BACKTRACE', 1); -/** - * @nodep Gtk - */ -if ('@include_path@' != '@'.'include_path'.'@') { - ini_set('include_path', '@include_path@'); - $raw = false; -} else { - // this is a raw, uninstalled pear, either a cvs checkout, or php distro - $raw = true; -} -@ini_set('allow_url_fopen', true); -if (!ini_get('safe_mode')) { - @set_time_limit(0); -} -ob_implicit_flush(true); -@ini_set('track_errors', true); -@ini_set('html_errors', false); -@ini_set('magic_quotes_runtime', false); -$_PEAR_PHPDIR = '#$%^&*'; -set_error_handler('error_handler'); - -$pear_package_version = "@pear_version@"; - -require_once 'PEAR.php'; -require_once 'PEAR/Frontend.php'; -require_once 'PEAR/Config.php'; -require_once 'PEAR/Command.php'; -require_once 'Console/Getopt.php'; - - -PEAR_Command::setFrontendType('CLI'); -$all_commands = PEAR_Command::getCommands(); - -// remove this next part when we stop supporting that crap-ass PHP 4.2 -if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) { - echo 'ERROR: either use the CLI php executable, or set register_argc_argv=On in php.ini'; - exit(1); -} - -$argv = Console_Getopt::readPHPArgv(); -// fix CGI sapi oddity - the -- in pear.bat/pear is not removed -if (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') { - unset($argv[1]); - $argv = array_values($argv); -} -$progname = PEAR_RUNTYPE; -array_shift($argv); -$options = Console_Getopt::getopt2($argv, "c:C:d:D:Gh?sSqu:vV"); -if (PEAR::isError($options)) { - usage($options); -} - -$opts = $options[0]; - -$fetype = 'CLI'; -if ($progname == 'gpear' || $progname == 'pear-gtk') { - $fetype = 'Gtk'; -} else { - foreach ($opts as $opt) { - if ($opt[0] == 'G') { - $fetype = 'Gtk'; - } - } -} -//Check if Gtk and PHP >= 5.1.0 -if ($fetype == 'Gtk' && version_compare(phpversion(), '5.1.0', '>=')) { - $fetype = 'Gtk2'; -} - -$pear_user_config = ''; -$pear_system_config = ''; -$store_user_config = false; -$store_system_config = false; -$verbose = 1; - -foreach ($opts as $opt) { - switch ($opt[0]) { - case 'c': - $pear_user_config = $opt[1]; - break; - case 'C': - $pear_system_config = $opt[1]; - break; - } -} - -PEAR_Command::setFrontendType($fetype); -$ui = &PEAR_Command::getFrontendObject(); -$config = &PEAR_Config::singleton($pear_user_config, $pear_system_config); - -if (PEAR::isError($config)) { - $_file = ''; - if ($pear_user_config !== false) { - $_file .= $pear_user_config; - } - if ($pear_system_config !== false) { - $_file .= '/' . $pear_system_config; - } - if ($_file == '/') { - $_file = 'The default config file'; - } - $config->getMessage(); - $ui->outputData("ERROR: $_file is not a valid config file or is corrupted."); - // We stop, we have no idea where we are :) - exit(1); -} - -// this is used in the error handler to retrieve a relative path -$_PEAR_PHPDIR = $config->get('php_dir'); -$ui->setConfig($config); -PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")); -if (ini_get('safe_mode')) { - $ui->outputData('WARNING: running in safe mode requires that all files created ' . - 'be the same uid as the current script. PHP reports this script is uid: ' . - @getmyuid() . ', and current user is: ' . @get_current_user()); -} - -$verbose = $config->get("verbose"); -$cmdopts = array(); - -if ($raw) { - if (!$config->isDefinedLayer('user') && !$config->isDefinedLayer('system')) { - $found = false; - foreach ($opts as $opt) { - if ($opt[0] == 'd' || $opt[0] == 'D') { - $found = true; // the user knows what they are doing, and are setting config values - } - } - if (!$found) { - // no prior runs, try to install PEAR - if (strpos(dirname(__FILE__), 'scripts')) { - $packagexml = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'package2.xml'; - $pearbase = dirname(dirname(__FILE__)); - } else { - $packagexml = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'package2.xml'; - $pearbase = dirname(__FILE__); - } - if (file_exists($packagexml)) { - $options[1] = array( - 'install', - $packagexml - ); - $config->set('php_dir', $pearbase . DIRECTORY_SEPARATOR . 'php'); - $config->set('data_dir', $pearbase . DIRECTORY_SEPARATOR . 'data'); - $config->set('doc_dir', $pearbase . DIRECTORY_SEPARATOR . 'docs'); - $config->set('test_dir', $pearbase . DIRECTORY_SEPARATOR . 'tests'); - $config->set('ext_dir', $pearbase . DIRECTORY_SEPARATOR . 'extensions'); - $config->set('bin_dir', $pearbase); - $config->mergeConfigFile($pearbase . 'pear.ini', false); - $config->store(); - $config->set('auto_discover', 1); - } - } - } -} -foreach ($opts as $opt) { - $param = !empty($opt[1]) ? $opt[1] : true; - switch ($opt[0]) { - case 'd': - if ($param === true) { - die('Invalid usage of "-d" option, expected -d config_value=value, ' . - 'received "-d"' . "\n"); - } - $possible = explode('=', $param); - if (count($possible) != 2) { - die('Invalid usage of "-d" option, expected -d config_value=value, received "' . - $param . '"' . "\n"); - } - list($key, $value) = explode('=', $param); - $config->set($key, $value, 'user'); - break; - case 'D': - if ($param === true) { - die('Invalid usage of "-d" option, expected -d config_value=value, ' . - 'received "-d"' . "\n"); - } - $possible = explode('=', $param); - if (count($possible) != 2) { - die('Invalid usage of "-d" option, expected -d config_value=value, received "' . - $param . '"' . "\n"); - } - list($key, $value) = explode('=', $param); - $config->set($key, $value, 'system'); - break; - case 's': - $store_user_config = true; - break; - case 'S': - $store_system_config = true; - break; - case 'u': - $config->remove($param, 'user'); - break; - case 'v': - $config->set('verbose', $config->get('verbose') + 1); - break; - case 'q': - $config->set('verbose', $config->get('verbose') - 1); - break; - case 'V': - usage(null, 'version'); - case 'c': - case 'C': - break; - default: - // all non pear params goes to the command - $cmdopts[$opt[0]] = $param; - break; - } -} - -if ($store_system_config) { - $config->store('system'); -} - -if ($store_user_config) { - $config->store('user'); -} - -$command = (isset($options[1][0])) ? $options[1][0] : null; -if (empty($command) && ($store_user_config || $store_system_config)) { - exit; -} - -if ($fetype == 'Gtk' || $fetype == 'Gtk2') { - if (!$config->validConfiguration()) { - PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' . - "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" . - 'file to one of these locations, or use the -c and -s options to create one'); - } - Gtk::main(); -} else do { - if ($command == 'help') { - usage(null, @$options[1][1]); - } - - if (!$config->validConfiguration()) { - PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' . - "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" . - 'file to one of these locations, or use the -c and -s options to create one'); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $cmd = PEAR_Command::factory($command, $config); - PEAR::popErrorHandling(); - if (PEAR::isError($cmd)) { - usage(null, @$options[1][0]); - } - - $short_args = $long_args = null; - PEAR_Command::getGetoptArgs($command, $short_args, $long_args); - array_shift($options[1]); - $tmp = Console_Getopt::getopt2($options[1], $short_args, $long_args); - - if (PEAR::isError($tmp)) { - break; - } - - list($tmpopt, $params) = $tmp; - $opts = array(); - foreach ($tmpopt as $foo => $tmp2) { - list($opt, $value) = $tmp2; - if ($value === null) { - $value = true; // options without args - } - - if (strlen($opt) == 1) { - $cmdoptions = $cmd->getOptions($command); - foreach ($cmdoptions as $o => $d) { - if (isset($d['shortopt']) && $d['shortopt'] == $opt) { - $opts[$o] = $value; - } - } - } else { - if (substr($opt, 0, 2) == '--') { - $opts[substr($opt, 2)] = $value; - } - } - } - - $ok = $cmd->run($command, $opts, $params); - if ($ok === false) { - PEAR::raiseError("unknown command `$command'"); - } - - if (PEAR::isError($ok)) { - PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")); - PEAR::raiseError($ok); - } -} while (false); - -// {{{ usage() - -function usage($error = null, $helpsubject = null) -{ - global $progname, $all_commands; - $stderr = fopen('php://stderr', 'w'); - if (PEAR::isError($error)) { - fputs($stderr, $error->getMessage() . "\n"); - } elseif ($error !== null) { - fputs($stderr, "$error\n"); - } - - if ($helpsubject != null) { - $put = cmdHelp($helpsubject); - } else { - $put = - "Commands:\n"; - $maxlen = max(array_map("strlen", $all_commands)); - $formatstr = "%-{$maxlen}s %s\n"; - ksort($all_commands); - foreach ($all_commands as $cmd => $class) { - $put .= sprintf($formatstr, $cmd, PEAR_Command::getDescription($cmd)); - } - $put .= - "Usage: $progname [options] command [command-options] \n". - "Type \"$progname help options\" to list all options.\n". - "Type \"$progname help shortcuts\" to list all command shortcuts.\n". - "Type \"$progname help \" to get the help for the specified command."; - } - fputs($stderr, "$put\n"); - fclose($stderr); - exit(1); -} - -function cmdHelp($command) -{ - global $progname, $all_commands, $config; - if ($command == "options") { - return - "Options:\n". - " -v increase verbosity level (default 1)\n". - " -q be quiet, decrease verbosity level\n". - " -c file find user configuration in `file'\n". - " -C file find system configuration in `file'\n". - " -d foo=bar set user config variable `foo' to `bar'\n". - " -D foo=bar set system config variable `foo' to `bar'\n". - " -G start in graphical (Gtk) mode\n". - " -s store user configuration\n". - " -S store system configuration\n". - " -u foo unset `foo' in the user configuration\n". - " -h, -? display help/usage (this message)\n". - " -V version information\n"; - } elseif ($command == "shortcuts") { - $sc = PEAR_Command::getShortcuts(); - $ret = "Shortcuts:\n"; - foreach ($sc as $s => $c) { - $ret .= sprintf(" %-8s %s\n", $s, $c); - } - return $ret; - - } elseif ($command == "version") { - return "PEAR Version: ".$GLOBALS['pear_package_version']. - "\nPHP Version: ".phpversion(). - "\nZend Engine Version: ".zend_version(). - "\nRunning on: ".php_uname(); - - } elseif ($help = PEAR_Command::getHelp($command)) { - if (is_string($help)) { - return "$progname $command [options] $help\n"; - } - - if ($help[1] === null) { - return "$progname $command $help[0]"; - } - - return "$progname $command [options] $help[0]\n$help[1]"; - } - - return "Command '$command' is not valid, try '$progname help'"; -} - -// }}} - -function error_handler($errno, $errmsg, $file, $line, $vars) { - if ((defined('E_STRICT') && $errno & E_STRICT) || (defined('E_DEPRECATED') && - $errno & E_DEPRECATED) || !error_reporting()) { - if (defined('E_STRICT') && $errno & E_STRICT) { - return; // E_STRICT - } - if (defined('E_DEPRECATED') && $errno & E_DEPRECATED) { - return; // E_DEPRECATED - } - if ($GLOBALS['config']->get('verbose') < 4) { - return false; // @silenced error, show all if debug is high enough - } - } - $errortype = array ( - E_ERROR => "Error", - E_WARNING => "Warning", - E_PARSE => "Parsing Error", - E_NOTICE => "Notice", - E_CORE_ERROR => "Core Error", - E_CORE_WARNING => "Core Warning", - E_COMPILE_ERROR => "Compile Error", - E_COMPILE_WARNING => "Compile Warning", - E_USER_ERROR => "User Error", - E_USER_WARNING => "User Warning", - E_USER_NOTICE => "User Notice" - ); - $prefix = $errortype[$errno]; - global $_PEAR_PHPDIR; - if (stristr($file, $_PEAR_PHPDIR)) { - $file = substr($file, strlen($_PEAR_PHPDIR) + 1); - } else { - $file = basename($file); - } - print "\n$prefix: $errmsg in $file on line $line\n"; - return false; -} - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: nil - * mode: php - * End: - */ -// vim600:syn=phpPEAR-1.9.0/scripts/peclcmd.php100664 764 764 1636 100664 11123 - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: peclcmd.php 276392 2009-02-25 00:06:23Z dufuz $ - * @link http://pear.php.net/package/PEAR - */ - -/** - * @nodep Gtk - */ -if ('@include_path@' != '@'.'include_path'.'@') { - ini_set('include_path', '@include_path@'); - $raw = false; -} else { - // this is a raw, uninstalled pear, either a cvs checkout, or php distro - $raw = true; -} -define('PEAR_RUNTYPE', 'pecl'); -require_once 'pearcmd.php'; -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: nil - * mode: php - * End: - */ -// vim600:syn=php - -?> -PEAR-1.9.0/LICENSE100664 764 764 2705 100664 6317 Copyright (c) 1997-2009, - Stig Bakken , - Gregory Beaver , - Helgi Þormar Þorbjörnsson , - Tomas V.V.Cox , - Martin Jansen . -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -PEAR-1.9.0/INSTALL100664 764 764 3641 100664 6343 PEAR - The PEAR Installer -========================= -Installing the PEAR Installer. - -You should install PEAR on a local development machine first. Installing -PEAR on a remote production machine should only be done after you are -familiar with PEAR and have tested code using PEAR on your development -machine. - -There are two methods of installing PEAR - - PEAR bundled in PHP - - go-pear - -We will first examine how to install PEAR that is bundled with PHP. - -Microsoft Windows -================= -If you are running PHP 5.2.0 or newer, simply download and -run the windows installer (.msi) and PEAR can be automatically -installed. - -Otherwise, for older PHP versions, download the .zip of windows, -there is a script included with your PHP distribution that is called -"go-pear". You must open a command box in order to run it. Click -"start" then click "Run..." and type "cmd.exe" to open a command box. -Use "cd" to change directory to the location of PHP where you unzipped it, -and run the go-pear command. - -Unix -==== -make sure you have enabled default extensions, and if you want faster -downloads, enable the zlib extension. You must also enable the CLI -SAPI with the --enable-cli extension directive. After this, simply run: - -make install-pear - -and PEAR will be automatically configured for you. - -go-pear -======= -For users who cannot perform the above steps, or who wish to obtain the -latest PEAR with a slightly higher risk of failure, use go-pear. go-pear -is obtained by downloading http://go-pear.org and saving it as go-pear.php. -After downloading, simply run "php go-pear.php" or open it in a web browser -(windows only) to download and install PEAR. - -You can always ask general installation questions on pear-general@lists.php.net, -a public mailing list devoted to support for PEAR packages and installation- -related issues. - -Happy PHPing, we hope PEAR will be a great tool for your development work! - -$Id: INSTALL 220345 2006-09-22 03:31:36Z cellog $PEAR-1.9.0/package.dtd100664 764 764 6477 100664 7414 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PEAR-1.9.0/PEAR5.php100664 764 764 2077 100664 6641 - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PEAR.php 286670 2009-08-02 14:16:06Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/**#@+ - * ERROR constants - */ -define('PEAR_ERROR_RETURN', 1); -define('PEAR_ERROR_PRINT', 2); -define('PEAR_ERROR_TRIGGER', 4); -define('PEAR_ERROR_DIE', 8); -define('PEAR_ERROR_CALLBACK', 16); -/** - * WARNING: obsolete - * @deprecated - */ -define('PEAR_ERROR_EXCEPTION', 32); -/**#@-*/ -define('PEAR_ZE2', (function_exists('version_compare') && - version_compare(zend_version(), "2-dev", "ge"))); - -if (substr(PHP_OS, 0, 3) == 'WIN') { - define('OS_WINDOWS', true); - define('OS_UNIX', false); - define('PEAR_OS', 'Windows'); -} else { - define('OS_WINDOWS', false); - define('OS_UNIX', true); - define('PEAR_OS', 'Unix'); // blatant assumption -} - -$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; -$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; -$GLOBALS['_PEAR_destructor_object_list'] = array(); -$GLOBALS['_PEAR_shutdown_funcs'] = array(); -$GLOBALS['_PEAR_error_handler_stack'] = array(); - -@ini_set('track_errors', true); - -/** - * Base class for other PEAR classes. Provides rudimentary - * emulation of destructors. - * - * If you want a destructor in your class, inherit PEAR and make a - * destructor method called _yourclassname (same name as the - * constructor, but with a "_" prefix). Also, in your constructor you - * have to call the PEAR constructor: $this->PEAR();. - * The destructor method will be called without parameters. Note that - * at in some SAPI implementations (such as Apache), any output during - * the request shutdown (in which destructors are called) seems to be - * discarded. If you need to get any debug information from your - * destructor, use error_log(), syslog() or something similar. - * - * IMPORTANT! To use the emulated destructors you need to create the - * objects by reference: $obj =& new PEAR_child; - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @see PEAR_Error - * @since Class available since PHP 4.0.2 - * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear - */ -class PEAR -{ - // {{{ properties - - /** - * Whether to enable internal debug messages. - * - * @var bool - * @access private - */ - var $_debug = false; - - /** - * Default error mode for this object. - * - * @var int - * @access private - */ - var $_default_error_mode = null; - - /** - * Default error options used for this object when error mode - * is PEAR_ERROR_TRIGGER. - * - * @var int - * @access private - */ - var $_default_error_options = null; - - /** - * Default error handler (callback) for this object, if error mode is - * PEAR_ERROR_CALLBACK. - * - * @var string - * @access private - */ - var $_default_error_handler = ''; - - /** - * Which class to use for error objects. - * - * @var string - * @access private - */ - var $_error_class = 'PEAR_Error'; - - /** - * An array of expected errors. - * - * @var array - * @access private - */ - var $_expected_errors = array(); - - // }}} - - // {{{ constructor - - /** - * Constructor. Registers this object in - * $_PEAR_destructor_object_list for destructor emulation if a - * destructor object exists. - * - * @param string $error_class (optional) which class to use for - * error objects, defaults to PEAR_Error. - * @access public - * @return void - */ - function PEAR($error_class = null) - { - $classname = strtolower(get_class($this)); - if ($this->_debug) { - print "PEAR constructor called, class=$classname\n"; - } - if ($error_class !== null) { - $this->_error_class = $error_class; - } - while ($classname && strcasecmp($classname, "pear")) { - $destructor = "_$classname"; - if (method_exists($this, $destructor)) { - global $_PEAR_destructor_object_list; - $_PEAR_destructor_object_list[] = &$this; - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - break; - } else { - $classname = get_parent_class($classname); - } - } - } - - // }}} - // {{{ destructor - - /** - * Destructor (the emulated type of...). Does nothing right now, - * but is included for forward compatibility, so subclass - * destructors should always call it. - * - * See the note in the class desciption about output from - * destructors. - * - * @access public - * @return void - */ - function _PEAR() { - if ($this->_debug) { - printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); - } - } - - // }}} - // {{{ getStaticProperty() - - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - function &getStaticProperty($class, $var) - { - static $properties; - if (!isset($properties[$class])) { - $properties[$class] = array(); - } - - if (!array_key_exists($var, $properties[$class])) { - $properties[$class][$var] = null; - } - - return $properties[$class][$var]; - } - - // }}} - // {{{ registerShutdownFunc() - - /** - * Use this function to register a shutdown method for static - * classes. - * - * @access public - * @param mixed $func The function name (or array of class/method) to call - * @param mixed $args The arguments to pass to the function - * @return void - */ - function registerShutdownFunc($func, $args = array()) - { - // if we are called statically, there is a potential - // that no shutdown func is registered. Bug #6445 - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); - } - - // }}} - // {{{ isError() - - /** - * Tell whether a value is a PEAR error. - * - * @param mixed $data the value to test - * @param int $code if $data is an error object, return true - * only if $code is a string and - * $obj->getMessage() == $code or - * $code is an integer and $obj->getCode() == $code - * @access public - * @return bool true if parameter is an error - */ - function isError($data, $code = null) - { - if (!is_a($data, 'PEAR_Error')) { - return false; - } - - if (is_null($code)) { - return true; - } elseif (is_string($code)) { - return $data->getMessage() == $code; - } - - return $data->getCode() == $code; - } - - // }}} - // {{{ setErrorHandling() - - /** - * Sets how errors generated by this object should be handled. - * Can be invoked both in objects and statically. If called - * statically, setErrorHandling sets the default behaviour for all - * PEAR objects. If called in an object, setErrorHandling sets - * the default behaviour for that object. - * - * @param int $mode - * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. - * - * @param mixed $options - * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one - * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * - * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected - * to be the callback function or method. A callback - * function is a string with the name of the function, a - * callback method is an array of two elements: the element - * at index 0 is the object, and the element at index 1 is - * the name of the method to call in the object. - * - * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is - * a printf format string used when printing the error - * message. - * - * @access public - * @return void - * @see PEAR_ERROR_RETURN - * @see PEAR_ERROR_PRINT - * @see PEAR_ERROR_TRIGGER - * @see PEAR_ERROR_DIE - * @see PEAR_ERROR_CALLBACK - * @see PEAR_ERROR_EXCEPTION - * - * @since PHP 4.0.5 - */ - - function setErrorHandling($mode = null, $options = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $setmode = &$this->_default_error_mode; - $setoptions = &$this->_default_error_options; - } else { - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - } - - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - } - - // }}} - // {{{ expectError() - - /** - * This method is used to tell which errors you expect to get. - * Expected errors are always returned with error mode - * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, - * and this method pushes a new element onto it. The list of - * expected errors are in effect until they are popped off the - * stack with the popExpect() method. - * - * Note that this method can not be called statically - * - * @param mixed $code a single error code or an array of error codes to expect - * - * @return int the new depth of the "expected errors" stack - * @access public - */ - function expectError($code = '*') - { - if (is_array($code)) { - array_push($this->_expected_errors, $code); - } else { - array_push($this->_expected_errors, array($code)); - } - return sizeof($this->_expected_errors); - } - - // }}} - // {{{ popExpect() - - /** - * This method pops one element off the expected error codes - * stack. - * - * @return array the list of error codes that were popped - */ - function popExpect() - { - return array_pop($this->_expected_errors); - } - - // }}} - // {{{ _checkDelExpect() - - /** - * This method checks unsets an error code if available - * - * @param mixed error code - * @return bool true if the error code was unset, false otherwise - * @access private - * @since PHP 4.3.0 - */ - function _checkDelExpect($error_code) - { - $deleted = false; - - foreach ($this->_expected_errors AS $key => $error_array) { - if (in_array($error_code, $error_array)) { - unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); - $deleted = true; - } - - // clean up empty arrays - if (0 == count($this->_expected_errors[$key])) { - unset($this->_expected_errors[$key]); - } - } - return $deleted; - } - - // }}} - // {{{ delExpect() - - /** - * This method deletes all occurences of the specified element from - * the expected error codes stack. - * - * @param mixed $error_code error code that should be deleted - * @return mixed list of error codes that were deleted or error - * @access public - * @since PHP 4.3.0 - */ - function delExpect($error_code) - { - $deleted = false; - if ((is_array($error_code) && (0 != count($error_code)))) { - // $error_code is a non-empty array here; - // we walk through it trying to unset all - // values - foreach($error_code as $key => $error) { - if ($this->_checkDelExpect($error)) { - $deleted = true; - } else { - $deleted = false; - } - } - return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } elseif (!empty($error_code)) { - // $error_code comes alone, trying to unset it - if ($this->_checkDelExpect($error_code)) { - return true; - } else { - return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } - } - - // $error_code is empty - return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME - } - - // }}} - // {{{ raiseError() - - /** - * This method is a wrapper that returns an instance of the - * configured error class with this object's default error - * handling applied. If the $mode and $options parameters are not - * specified, the object's defaults are used. - * - * @param mixed $message a text error message or a PEAR error object - * - * @param int $code a numeric error code (it is up to your class - * to define these if you want to use codes) - * - * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. - * - * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter - * specifies the PHP-internal error level (one of - * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * If $mode is PEAR_ERROR_CALLBACK, this - * parameter specifies the callback function or - * method. In other error modes this parameter - * is ignored. - * - * @param string $userinfo If you need to pass along for example debug - * information, this parameter is meant for that. - * - * @param string $error_class The returned error object will be - * instantiated from this class, if specified. - * - * @param bool $skipmsg If true, raiseError will only pass error codes, - * the error message parameter will be dropped. - * - * @access public - * @return object a PEAR error object - * @see PEAR::setErrorHandling - * @since PHP 4.0.5 - */ - function &raiseError($message = null, - $code = null, - $mode = null, - $options = null, - $userinfo = null, - $error_class = null, - $skipmsg = false) - { - // The error is yet a PEAR error object - if (is_object($message)) { - $code = $message->getCode(); - $userinfo = $message->getUserInfo(); - $error_class = $message->getType(); - $message->error_message_prefix = ''; - $message = $message->getMessage(); - } - - if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { - if ($exp[0] == "*" || - (is_int(reset($exp)) && in_array($code, $exp)) || - (is_string(reset($exp)) && in_array($message, $exp))) { - $mode = PEAR_ERROR_RETURN; - } - } - - // No mode given, try global ones - if ($mode === null) { - // Class error handler - if (isset($this) && isset($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - $options = $this->_default_error_options; - // Global error handler - } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { - $mode = $GLOBALS['_PEAR_default_error_mode']; - $options = $GLOBALS['_PEAR_default_error_options']; - } - } - - if ($error_class !== null) { - $ec = $error_class; - } elseif (isset($this) && isset($this->_error_class)) { - $ec = $this->_error_class; - } else { - $ec = 'PEAR_Error'; - } - - if (intval(PHP_VERSION) < 5) { - // little non-eval hack to fix bug #12147 - include 'PEAR/FixPHP5PEARWarnings.php'; - return $a; - } - - if ($skipmsg) { - $a = new $ec($code, $mode, $options, $userinfo); - } else { - $a = new $ec($message, $code, $mode, $options, $userinfo); - } - - return $a; - } - - // }}} - // {{{ throwError() - - /** - * Simpler form of raiseError with fewer options. In most cases - * message, code and userinfo are enough. - * - * @param string $message - * - */ - function &throwError($message = null, - $code = null, - $userinfo = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $a = &$this->raiseError($message, $code, null, null, $userinfo); - return $a; - } - - $a = &PEAR::raiseError($message, $code, null, null, $userinfo); - return $a; - } - - // }}} - function staticPushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - $stack[] = array($def_mode, $def_options); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $def_mode = $mode; - $def_options = $options; - break; - - case PEAR_ERROR_CALLBACK: - $def_mode = $mode; - // class/object method callback - if (is_callable($options)) { - $def_options = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - $stack[] = array($mode, $options); - return true; - } - - function staticPopErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - return true; - } - - // {{{ pushErrorHandling() - - /** - * Push a new error handler on top of the error handler options stack. With this - * you can easily override the actual error handler for some code and restore - * it later with popErrorHandling. - * - * @param mixed $mode (same as setErrorHandling) - * @param mixed $options (same as setErrorHandling) - * - * @return bool Always true - * - * @see PEAR::setErrorHandling - */ - function pushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - if (isset($this) && is_a($this, 'PEAR')) { - $def_mode = &$this->_default_error_mode; - $def_options = &$this->_default_error_options; - } else { - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - } - $stack[] = array($def_mode, $def_options); - - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); - } - $stack[] = array($mode, $options); - return true; - } - - // }}} - // {{{ popErrorHandling() - - /** - * Pop the last error handler used - * - * @return bool Always true - * - * @see PEAR::pushErrorHandling - */ - function popErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); - } - return true; - } - - // }}} - // {{{ loadExtension() - - /** - * OS independant PHP extension load. Remember to take care - * on the correct extension name for case sensitive OSes. - * - * @param string $ext The extension name - * @return bool Success or not on the dl() call - */ - function loadExtension($ext) - { - if (!extension_loaded($ext)) { - // if either returns true dl() will produce a FATAL error, stop that - if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { - return false; - } - - if (OS_WINDOWS) { - $suffix = '.dll'; - } elseif (PHP_OS == 'HP-UX') { - $suffix = '.sl'; - } elseif (PHP_OS == 'AIX') { - $suffix = '.a'; - } elseif (PHP_OS == 'OSX') { - $suffix = '.bundle'; - } else { - $suffix = '.so'; - } - - return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); - } - - return true; - } - - // }}} -} - -if (PEAR_ZE2) { - include_once 'PEAR5.php'; -} - -// {{{ _PEAR_call_destructors() - -function _PEAR_call_destructors() -{ - global $_PEAR_destructor_object_list; - if (is_array($_PEAR_destructor_object_list) && - sizeof($_PEAR_destructor_object_list)) - { - reset($_PEAR_destructor_object_list); - if (PEAR_ZE2) { - $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); - } else { - $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); - } - - if ($destructLifoExists) { - $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); - } - - while (list($k, $objref) = each($_PEAR_destructor_object_list)) { - $classname = get_class($objref); - while ($classname) { - $destructor = "_$classname"; - if (method_exists($objref, $destructor)) { - $objref->$destructor(); - break; - } else { - $classname = get_parent_class($classname); - } - } - } - // Empty the object list to ensure that destructors are - // not called more than once. - $_PEAR_destructor_object_list = array(); - } - - // Now call the shutdown functions - if (isset($GLOBALS['_PEAR_shutdown_funcs']) AND is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { - foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { - call_user_func_array($value[0], $value[1]); - } - } -} - -// }}} -/** - * Standard PEAR error class for PHP 4 - * - * This class is supserseded by {@link PEAR_Exception} in PHP 5 - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Gregory Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/manual/en/core.pear.pear-error.php - * @see PEAR::raiseError(), PEAR::throwError() - * @since Class available since PHP 4.0.2 - */ -class PEAR_Error -{ - // {{{ properties - - var $error_message_prefix = ''; - var $mode = PEAR_ERROR_RETURN; - var $level = E_USER_NOTICE; - var $code = -1; - var $message = ''; - var $userinfo = ''; - var $backtrace = null; - - // }}} - // {{{ constructor - - /** - * PEAR_Error constructor - * - * @param string $message message - * - * @param int $code (optional) error code - * - * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, - * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION - * - * @param mixed $options (optional) error level, _OR_ in the case of - * PEAR_ERROR_CALLBACK, the callback function or object/method - * tuple. - * - * @param string $userinfo (optional) additional user/debug info - * - * @access public - * - */ - function PEAR_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { - if ($mode === null) { - $mode = PEAR_ERROR_RETURN; - } - $this->message = $message; - $this->code = $code; - $this->mode = $mode; - $this->userinfo = $userinfo; - - if (PEAR_ZE2) { - $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); - } else { - $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); - } - - if (!$skiptrace) { - $this->backtrace = debug_backtrace(); - if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { - unset($this->backtrace[0]['object']); - } - } - - if ($mode & PEAR_ERROR_CALLBACK) { - $this->level = E_USER_NOTICE; - $this->callback = $options; - } else { - if ($options === null) { - $options = E_USER_NOTICE; - } - - $this->level = $options; - $this->callback = null; - } - - if ($this->mode & PEAR_ERROR_PRINT) { - if (is_null($options) || is_int($options)) { - $format = "%s"; - } else { - $format = $options; - } - - printf($format, $this->getMessage()); - } - - if ($this->mode & PEAR_ERROR_TRIGGER) { - trigger_error($this->getMessage(), $this->level); - } - - if ($this->mode & PEAR_ERROR_DIE) { - $msg = $this->getMessage(); - if (is_null($options) || is_int($options)) { - $format = "%s"; - if (substr($msg, -1) != "\n") { - $msg .= "\n"; - } - } else { - $format = $options; - } - die(sprintf($format, $msg)); - } - - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_callable($this->callback)) { - call_user_func($this->callback, $this); - } - } - - if ($this->mode & PEAR_ERROR_EXCEPTION) { - trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); - eval('$e = new Exception($this->message, $this->code);throw($e);'); - } - } - - // }}} - // {{{ getMode() - - /** - * Get the error mode from an error object. - * - * @return int error mode - * @access public - */ - function getMode() { - return $this->mode; - } - - // }}} - // {{{ getCallback() - - /** - * Get the callback function/method from an error object. - * - * @return mixed callback function or object/method array - * @access public - */ - function getCallback() { - return $this->callback; - } - - // }}} - // {{{ getMessage() - - - /** - * Get the error message from an error object. - * - * @return string full error message - * @access public - */ - function getMessage() - { - return ($this->error_message_prefix . $this->message); - } - - - // }}} - // {{{ getCode() - - /** - * Get error code from an error object - * - * @return int error code - * @access public - */ - function getCode() - { - return $this->code; - } - - // }}} - // {{{ getType() - - /** - * Get the name of this error/exception. - * - * @return string error/exception name (type) - * @access public - */ - function getType() - { - return get_class($this); - } - - // }}} - // {{{ getUserInfo() - - /** - * Get additional user-supplied information. - * - * @return string user-supplied information - * @access public - */ - function getUserInfo() - { - return $this->userinfo; - } - - // }}} - // {{{ getDebugInfo() - - /** - * Get additional debug information supplied by the application. - * - * @return string debug information - * @access public - */ - function getDebugInfo() - { - return $this->getUserInfo(); - } - - // }}} - // {{{ getBacktrace() - - /** - * Get the call backtrace from where the error was generated. - * Supported with PHP 4.3.0 or newer. - * - * @param int $frame (optional) what frame to fetch - * @return array Backtrace, or NULL if not available. - * @access public - */ - function getBacktrace($frame = null) - { - if (defined('PEAR_IGNORE_BACKTRACE')) { - return null; - } - if ($frame === null) { - return $this->backtrace; - } - return $this->backtrace[$frame]; - } - - // }}} - // {{{ addUserInfo() - - function addUserInfo($info) - { - if (empty($this->userinfo)) { - $this->userinfo = $info; - } else { - $this->userinfo .= " ** $info"; - } - } - - // }}} - // {{{ toString() - function __toString() - { - return $this->getMessage(); - } - // }}} - // {{{ toString() - - /** - * Make a string representation of this object. - * - * @return string a string with an object summary - * @access public - */ - function toString() { - $modes = array(); - $levels = array(E_USER_NOTICE => 'notice', - E_USER_WARNING => 'warning', - E_USER_ERROR => 'error'); - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_array($this->callback)) { - $callback = (is_object($this->callback[0]) ? - strtolower(get_class($this->callback[0])) : - $this->callback[0]) . '::' . - $this->callback[1]; - } else { - $callback = $this->callback; - } - return sprintf('[%s: message="%s" code=%d mode=callback '. - 'callback=%s prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - $callback, $this->error_message_prefix, - $this->userinfo); - } - if ($this->mode & PEAR_ERROR_PRINT) { - $modes[] = 'print'; - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - $modes[] = 'trigger'; - } - if ($this->mode & PEAR_ERROR_DIE) { - $modes[] = 'die'; - } - if ($this->mode & PEAR_ERROR_RETURN) { - $modes[] = 'return'; - } - return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. - 'prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - implode("|", $modes), $levels[$this->level], - $this->error_message_prefix, - $this->userinfo); - } - - // }}} -} - -/* - * Local Variables: - * mode: php - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ -PEAR-1.9.0/README100664 764 764 2246 100664 6172 PEAR - The PEAR Installer -========================= - -What is the PEAR Installer? What is PEAR? - -PEAR is the PHP Extension and Application Repository, found at -http://pear.php.net. The PEAR Installer is this software, which -contains executable files and PHP code that is used to download -and install PEAR code from pear.php.net. - -PEAR contains useful software libraries and applications such as -MDB2 (database abstraction), HTML_QuickForm (HTML forms management), -PhpDocumentor (auto-documentation generator), DB_DataObject -(Data Access Abstraction), and many hundreds more. Browse all -available packages at http://pear.php.net, the list is constantly -growing and updating to reflect improvements in the PHP language. - -DOCUMENTATION -============= - -Documentation for PEAR can be found at http://pear.php.net/manual/. -Installation documentation can be found in the INSTALL file included -in this tarball. - -WARNING: DO NOT RUN PEAR WITHOUT INSTALLING IT - if you downloaded this -tarball manually, you MUST install it. Read the instructions in INSTALL -prior to use. - - -Happy PHPing, we hope PEAR will be a great tool for your development work! - -$Id: README 220345 2006-09-22 03:31:36Z cellog $PEAR-1.9.0/System.php100664 764 764 46777 100664 7350 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: System.php 276386 2009-02-24 23:52:56Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR.php'; -require_once 'Console/Getopt.php'; - -$GLOBALS['_System_temp_files'] = array(); - -/** -* System offers cross plattform compatible system functions -* -* Static functions for different operations. Should work under -* Unix and Windows. The names and usage has been taken from its respectively -* GNU commands. The functions will return (bool) false on error and will -* trigger the error with the PHP trigger_error() function (you can silence -* the error by prefixing a '@' sign after the function call, but this -* is not recommended practice. Instead use an error handler with -* {@link set_error_handler()}). -* -* Documentation on this class you can find in: -* http://pear.php.net/manual/ -* -* Example usage: -* if (!@System::rm('-r file1 dir1')) { -* print "could not delete file1 or dir1"; -* } -* -* In case you need to to pass file names with spaces, -* pass the params as an array: -* -* System::rm(array('-r', $file1, $dir1)); -* -* @category pear -* @package System -* @author Tomas V.V. Cox -* @copyright 1997-2006 The PHP Group -* @license http://opensource.org/licenses/bsd-license.php New BSD License -* @version Release: 1.9.0 -* @link http://pear.php.net/package/PEAR -* @since Class available since Release 0.1 -* @static -*/ -class System -{ - /** - * returns the commandline arguments of a function - * - * @param string $argv the commandline - * @param string $short_options the allowed option short-tags - * @param string $long_options the allowed option long-tags - * @return array the given options and there values - * @static - * @access private - */ - function _parseArgs($argv, $short_options, $long_options = null) - { - if (!is_array($argv) && $argv !== null) { - $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY); - } - return Console_Getopt::getopt2($argv, $short_options); - } - - /** - * Output errors with PHP trigger_error(). You can silence the errors - * with prefixing a "@" sign to the function call: @System::mkdir(..); - * - * @param mixed $error a PEAR error or a string with the error message - * @return bool false - * @static - * @access private - */ - function raiseError($error) - { - if (PEAR::isError($error)) { - $error = $error->getMessage(); - } - trigger_error($error, E_USER_WARNING); - return false; - } - - /** - * Creates a nested array representing the structure of a directory - * - * System::_dirToStruct('dir1', 0) => - * Array - * ( - * [dirs] => Array - * ( - * [0] => dir1 - * ) - * - * [files] => Array - * ( - * [0] => dir1/file2 - * [1] => dir1/file3 - * ) - * ) - * @param string $sPath Name of the directory - * @param integer $maxinst max. deep of the lookup - * @param integer $aktinst starting deep of the lookup - * @param bool $silent if true, do not emit errors. - * @return array the structure of the dir - * @static - * @access private - */ - function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) - { - $struct = array('dirs' => array(), 'files' => array()); - if (($dir = @opendir($sPath)) === false) { - if (!$silent) { - System::raiseError("Could not open dir $sPath"); - } - return $struct; // XXX could not open error - } - - $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? - $list = array(); - while (false !== ($file = readdir($dir))) { - if ($file != '.' && $file != '..') { - $list[] = $file; - } - } - - closedir($dir); - natsort($list); - if ($aktinst < $maxinst || $maxinst == 0) { - foreach ($list as $val) { - $path = $sPath . DIRECTORY_SEPARATOR . $val; - if (is_dir($path) && !is_link($path)) { - $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); - $struct = array_merge_recursive($struct, $tmp); - } else { - $struct['files'][] = $path; - } - } - } - - return $struct; - } - - /** - * Creates a nested array representing the structure of a directory and files - * - * @param array $files Array listing files and dirs - * @return array - * @static - * @see System::_dirToStruct() - */ - function _multipleToStruct($files) - { - $struct = array('dirs' => array(), 'files' => array()); - settype($files, 'array'); - foreach ($files as $file) { - if (is_dir($file) && !is_link($file)) { - $tmp = System::_dirToStruct($file, 0); - $struct = array_merge_recursive($tmp, $struct); - } else { - if (!in_array($file, $struct['files'])) { - $struct['files'][] = $file; - } - } - } - return $struct; - } - - /** - * The rm command for removing files. - * Supports multiple files and dirs and also recursive deletes - * - * @param string $args the arguments for rm - * @return mixed PEAR_Error or true for success - * @static - * @access public - */ - function rm($args) - { - $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - foreach ($opts[0] as $opt) { - if ($opt[0] == 'r') { - $do_recursive = true; - } - } - $ret = true; - if (isset($do_recursive)) { - $struct = System::_multipleToStruct($opts[1]); - foreach ($struct['files'] as $file) { - if (!@unlink($file)) { - $ret = false; - } - } - - rsort($struct['dirs']); - foreach ($struct['dirs'] as $dir) { - if (!@rmdir($dir)) { - $ret = false; - } - } - } else { - foreach ($opts[1] as $file) { - $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; - if (!@$delete($file)) { - $ret = false; - } - } - } - return $ret; - } - - /** - * Make directories. - * - * The -p option will create parent directories - * @param string $args the name of the director(y|ies) to create - * @return bool True for success - * @static - * @access public - */ - function mkDir($args) - { - $opts = System::_parseArgs($args, 'pm:'); - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - - $mode = 0777; // default mode - foreach ($opts[0] as $opt) { - if ($opt[0] == 'p') { - $create_parents = true; - } elseif ($opt[0] == 'm') { - // if the mode is clearly an octal number (starts with 0) - // convert it to decimal - if (strlen($opt[1]) && $opt[1]{0} == '0') { - $opt[1] = octdec($opt[1]); - } else { - // convert to int - $opt[1] += 0; - } - $mode = $opt[1]; - } - } - - $ret = true; - if (isset($create_parents)) { - foreach ($opts[1] as $dir) { - $dirstack = array(); - while ((!file_exists($dir) || !is_dir($dir)) && - $dir != DIRECTORY_SEPARATOR) { - array_unshift($dirstack, $dir); - $dir = dirname($dir); - } - - while ($newdir = array_shift($dirstack)) { - if (!is_writeable(dirname($newdir))) { - $ret = false; - break; - } - - if (!mkdir($newdir, $mode)) { - $ret = false; - } - } - } - } else { - foreach($opts[1] as $dir) { - if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { - $ret = false; - } - } - } - - return $ret; - } - - /** - * Concatenate files - * - * Usage: - * 1) $var = System::cat('sample.txt test.txt'); - * 2) System::cat('sample.txt test.txt > final.txt'); - * 3) System::cat('sample.txt test.txt >> final.txt'); - * - * Note: as the class use fopen, urls should work also (test that) - * - * @param string $args the arguments - * @return boolean true on success - * @static - * @access public - */ - function &cat($args) - { - $ret = null; - $files = array(); - if (!is_array($args)) { - $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); - } - - $count_args = count($args); - for ($i = 0; $i < $count_args; $i++) { - if ($args[$i] == '>') { - $mode = 'wb'; - $outputfile = $args[$i+1]; - break; - } elseif ($args[$i] == '>>') { - $mode = 'ab+'; - $outputfile = $args[$i+1]; - break; - } else { - $files[] = $args[$i]; - } - } - $outputfd = false; - if (isset($mode)) { - if (!$outputfd = fopen($outputfile, $mode)) { - $err = System::raiseError("Could not open $outputfile"); - return $err; - } - $ret = true; - } - foreach ($files as $file) { - if (!$fd = fopen($file, 'r')) { - System::raiseError("Could not open $file"); - continue; - } - while ($cont = fread($fd, 2048)) { - if (is_resource($outputfd)) { - fwrite($outputfd, $cont); - } else { - $ret .= $cont; - } - } - fclose($fd); - } - if (is_resource($outputfd)) { - fclose($outputfd); - } - return $ret; - } - - /** - * Creates temporary files or directories. This function will remove - * the created files when the scripts finish its execution. - * - * Usage: - * 1) $tempfile = System::mktemp("prefix"); - * 2) $tempdir = System::mktemp("-d prefix"); - * 3) $tempfile = System::mktemp(); - * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); - * - * prefix -> The string that will be prepended to the temp name - * (defaults to "tmp"). - * -d -> A temporary dir will be created instead of a file. - * -t -> The target dir where the temporary (file|dir) will be created. If - * this param is missing by default the env vars TMP on Windows or - * TMPDIR in Unix will be used. If these vars are also missing - * c:\windows\temp or /tmp will be used. - * - * @param string $args The arguments - * @return mixed the full path of the created (file|dir) or false - * @see System::tmpdir() - * @static - * @access public - */ - function mktemp($args = null) - { - static $first_time = true; - $opts = System::_parseArgs($args, 't:d'); - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - - foreach ($opts[0] as $opt) { - if ($opt[0] == 'd') { - $tmp_is_dir = true; - } elseif ($opt[0] == 't') { - $tmpdir = $opt[1]; - } - } - - $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; - if (!isset($tmpdir)) { - $tmpdir = System::tmpdir(); - } - - if (!System::mkDir(array('-p', $tmpdir))) { - return false; - } - - $tmp = tempnam($tmpdir, $prefix); - if (isset($tmp_is_dir)) { - unlink($tmp); // be careful possible race condition here - if (!mkdir($tmp, 0700)) { - return System::raiseError("Unable to create temporary directory $tmpdir"); - } - } - - $GLOBALS['_System_temp_files'][] = $tmp; - if (isset($tmp_is_dir)) { - //$GLOBALS['_System_temp_files'][] = dirname($tmp); - } - - if ($first_time) { - PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); - $first_time = false; - } - - return $tmp; - } - - /** - * Remove temporary files created my mkTemp. This function is executed - * at script shutdown time - * - * @static - * @access private - */ - function _removeTmpFiles() - { - if (count($GLOBALS['_System_temp_files'])) { - $delete = $GLOBALS['_System_temp_files']; - array_unshift($delete, '-r'); - System::rm($delete); - $GLOBALS['_System_temp_files'] = array(); - } - } - - /** - * Get the path of the temporal directory set in the system - * by looking in its environments variables. - * Note: php.ini-recommended removes the "E" from the variables_order setting, - * making unavaible the $_ENV array, that s why we do tests with _ENV - * - * @static - * @return string The temporary directory on the system - */ - function tmpdir() - { - if (OS_WINDOWS) { - if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { - return $var; - } - if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { - return $var; - } - if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { - return $var; - } - if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { - return $var; - } - return getenv('SystemRoot') . '\temp'; - } - if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { - return $var; - } - return realpath('/tmp'); - } - - /** - * The "which" command (show the full path of a command) - * - * @param string $program The command to search for - * @param mixed $fallback Value to return if $program is not found - * - * @return mixed A string with the full path or false if not found - * @static - * @author Stig Bakken - */ - function which($program, $fallback = false) - { - // enforce API - if (!is_string($program) || '' == $program) { - return $fallback; - } - - // full path given - if (basename($program) != $program) { - $path_elements[] = dirname($program); - $program = basename($program); - } else { - // Honor safe mode - if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) { - $path = getenv('PATH'); - if (!$path) { - $path = getenv('Path'); // some OSes are just stupid enough to do this - } - } - $path_elements = explode(PATH_SEPARATOR, $path); - } - - if (OS_WINDOWS) { - $exe_suffixes = getenv('PATHEXT') - ? explode(PATH_SEPARATOR, getenv('PATHEXT')) - : array('.exe','.bat','.cmd','.com'); - // allow passing a command.exe param - if (strpos($program, '.') !== false) { - array_unshift($exe_suffixes, ''); - } - // is_executable() is not available on windows for PHP4 - $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file'; - } else { - $exe_suffixes = array(''); - $pear_is_executable = 'is_executable'; - } - - foreach ($exe_suffixes as $suff) { - foreach ($path_elements as $dir) { - $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; - if (@$pear_is_executable($file)) { - return $file; - } - } - } - return $fallback; - } - - /** - * The "find" command - * - * Usage: - * - * System::find($dir); - * System::find("$dir -type d"); - * System::find("$dir -type f"); - * System::find("$dir -name *.php"); - * System::find("$dir -name *.php -name *.htm*"); - * System::find("$dir -maxdepth 1"); - * - * Params implmented: - * $dir -> Start the search at this directory - * -type d -> return only directories - * -type f -> return only files - * -maxdepth -> max depth of recursion - * -name -> search pattern (bash style). Multiple -name param allowed - * - * @param mixed Either array or string with the command line - * @return array Array of found files - * @static - * - */ - function find($args) - { - if (!is_array($args)) { - $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); - } - $dir = realpath(array_shift($args)); - if (!$dir) { - return array(); - } - $patterns = array(); - $depth = 0; - $do_files = $do_dirs = true; - $args_count = count($args); - for ($i = 0; $i < $args_count; $i++) { - switch ($args[$i]) { - case '-type': - if (in_array($args[$i+1], array('d', 'f'))) { - if ($args[$i+1] == 'd') { - $do_files = false; - } else { - $do_dirs = false; - } - } - $i++; - break; - case '-name': - $name = preg_quote($args[$i+1], '#'); - // our magic characters ? and * have just been escaped, - // so now we change the escaped versions to PCRE operators - $name = strtr($name, array('\?' => '.', '\*' => '.*')); - $patterns[] = '('.$name.')'; - $i++; - break; - case '-maxdepth': - $depth = $args[$i+1]; - break; - } - } - $path = System::_dirToStruct($dir, $depth, 0, true); - if ($do_files && $do_dirs) { - $files = array_merge($path['files'], $path['dirs']); - } elseif ($do_dirs) { - $files = $path['dirs']; - } else { - $files = $path['files']; - } - if (count($patterns)) { - $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); - $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; - $ret = array(); - $files_count = count($files); - for ($i = 0; $i < $files_count; $i++) { - // only search in the part of the file below the current directory - $filepart = basename($files[$i]); - if (preg_match($pattern, $filepart)) { - $ret[] = $files[$i]; - } - } - return $ret; - } - return $files; - } -}PEAR-1.9.0/template.spec100664 764 764 3725 100664 10004 Summary: PEAR: @summary@ -Name: @rpm_package@ -Version: @version@ -Release: 1 -License: @release_license@ -Group: Development/Libraries -Source: http://@master_server@/get/@package@-%{version}.tgz -BuildRoot: %{_tmppath}/%{name}-root -URL: http://@master_server@/package/@package@ -Prefix: %{_prefix} -BuildArchitectures: @arch@ -@extra_headers@ - -%description -@description@ - -%prep -rm -rf %{buildroot}/* -%setup -c -T -# XXX Source files location is missing here in pear cmd -pear -v -c %{buildroot}/pearrc \ - -d php_dir=%{_libdir}/php/pear \ - -d doc_dir=/docs \ - -d bin_dir=%{_bindir} \ - -d data_dir=%{_libdir}/php/pear/data \ - -d test_dir=%{_libdir}/php/pear/tests \ - -d ext_dir=%{_libdir} \@extra_config@ - -s - -%build -echo BuildRoot=%{buildroot} - -%postun -# if refcount = 0 then package has been removed (not upgraded) -if [ "$1" -eq "0" ]; then - pear uninstall --nodeps -r @possible_channel@@package@ - rm @rpm_xml_dir@/@package@.xml -fi - - -%post -# if refcount = 2 then package has been upgraded -if [ "$1" -ge "2" ]; then - pear upgrade --nodeps -r @rpm_xml_dir@/@package@.xml -else - pear install --nodeps -r @rpm_xml_dir@/@package@.xml -fi - -%install -pear -c %{buildroot}/pearrc install --nodeps -R %{buildroot} \ - $RPM_SOURCE_DIR/@package@-%{version}.tgz -rm %{buildroot}/pearrc -rm %{buildroot}/%{_libdir}/php/pear/.filemap -rm %{buildroot}/%{_libdir}/php/pear/.lock -rm -rf %{buildroot}/%{_libdir}/php/pear/.registry -if [ "@doc_files@" != "" ]; then - mv %{buildroot}/docs/@package@/* . - rm -rf %{buildroot}/docs -fi -mkdir -p %{buildroot}@rpm_xml_dir@ -tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package@package2xml@.xml -cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml - -#rm -rf %{buildroot}/* -#pear -q install -R %{buildroot} -n package@package2xml@.xml -#mkdir -p %{buildroot}@rpm_xml_dir@ -#cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml - -%files - %defattr(-,root,root) - %doc @doc_files@ - / -package.xml100664 764 764 76000 100664 6254 - - - PEAR - PEAR Base System - The PEAR package contains: - * the PEAR installer, for creating, distributing - and installing packages - * the PEAR_Exception PHP5 error handling mechanism - * the PEAR_ErrorStack advanced error handling mechanism - * the PEAR_Error error handling mechanism - * the OS_Guess class for retrieving info about the OS - where PHP is running on - * the System class for quick handling of common operations - with files and directories - * the PEAR base class - - Features in a nutshell: - * full support for channels - * pre-download dependency validation - * new package.xml 2.0 format allows tremendous flexibility while maintaining BC - * support for optional dependency groups and limited support for sub-packaging - * robust dependency support - * full dependency validation on uninstall - * remote install for hosts with only ftp access - no more problems with - restricted host installation - * full support for mirroring - * support for bundling several packages into a single tarball - * support for static dependencies on a url-based package - * support for custom file roles and installation tasks - - - - cellog - Greg Beaver - cellog@php.net - lead - - - pajoye - Pierre-Alain Joye - pierre@php.net - lead - - - ssb - Stig Bakken - stig@php.net - lead - - - cox - Tomas V.V.Cox - cox@idecnet.com - lead - - - dufuz - Helgi Thormar - dufuz@php.net - lead - - - tias - Tias Guns - tias@php.net - developer - - - timj - Tim Jackson - timj@php.net - helper - - - toggg - Bertrand Gugger - toggg@php.net - helper - - - mj - Martin Jansen - mj@php.net - helper - - - - 1.9.0 - 2009-09-03 - New BSD License - stable - * Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] - - - - PEAR - Archive_Tar - Console_Getopt - Structures_Graph - PEAR_Frontend_Web - PEAR_Frontend_Gtk - xml - pcre - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.8.0alpha1 - 2009-03-09 - New BSD License - alpha - * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] -* Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] -* Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] -* Implement Request #11170: script to generate Command/[command].xml [dufuz] -* Implement Request #11176: improve channel ... has updated its protocols message [dufuz] -* Implement Request #12706: pear list -a hard to read [dufuz] -* Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] -* Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] -* Implement Request #13927: install-pear.php should have option to set www_dir [timj] -* Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] -* Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. -* Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades -* Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] -* Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] -* Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] -* Fix PHP Bug #47323: strotime warnings in make install [dufuz] -* Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] -* Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] -* Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] -* Fix Bug #13953: config-set/config-show with channel alias fail [cellog] -* Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] -* Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] -* Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] -* Fix Bug #14210: pear list -ia brings warnings [dufuz] -* Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] -* Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] -* Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] -* Fix Bug #14437: openbasedir warning when loading config [dufuz] -* Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] -* Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] -* Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] -* Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] -* Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] -* Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] -NOTE! -Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment -to migrate over to one of the alternatives that have ben provided: -* PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) -* PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) -* PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) -* PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) -* PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) -* PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) -* PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) -* PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) -* PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) -* PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) -PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls -pear upgrade -f PEAR will allow people with lower versions -to upgrade to this release but no guarantees will be made that it will work properly. -Support for XML RPC channels has been dropped - The only ones that used it -(pear.php.net and pecl.php.net) have used the REST interface for years now. -SOAP support also removed as it was only proof of concept. -Move codebase from the PHP License to New BSD 2 clause license - - - - 1.8.0RC1 - 2009-03-27 - New BSD License - beta - * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] -* Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] -* Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] -* Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] - - - - - - New BSD License - Changes since RC1: - * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] - * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] - * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] - - Remove custom XML_Util class in favor of using upstream XML_Util package as dependency - -RC1 Release Notes: - * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] - * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] - - * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] - * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] - -Alpha1 Release Notes: - * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] - * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] - * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] - * Implement Request #11170: script to generate Command/[command].xml [dufuz] - * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] - * Implement Request #12706: pear list -a hard to read [dufuz] - * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] - * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] - * Implement Request #13927: install-pear.php should have option to set www_dir [timj] - * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] - * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. - * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades - * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] - * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] - - * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] - * Fix PHP Bug #47323: strotime warnings in make install [dufuz] - - * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] - * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] - * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] - * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] - * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] - * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] - * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] - * Fix Bug #14210: pear list -ia brings warnings [dufuz] - * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] - * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] - * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] - * Fix Bug #14437: openbasedir warning when loading config [dufuz] - * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] - * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] - * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] - * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] - * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] - * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] - - NOTE! - Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment - to migrate over to one of the alternatives that have ben provided: - * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) - * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) - * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) - * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) - * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) - * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) - * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) - * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) - * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) - * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) - - PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls - pear upgrade -f PEAR will allow people with lower versions - to upgrade to this release but no guarantees will be made that it will work properly. - - Support for XML RPC channels has been dropped - The only ones that used it - (pear.php.net and pecl.php.net) have used the REST interface for years now. - SOAP support also removed as it was only proof of concept. - - Move codebase from the PHP License to New BSD 2 clause license - - - - 1.8.1 - 2009-04-15 - New BSD License - stable - * Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz] - - - - 1.9.0RC1 - 2009-08-18 - New BSD License - beta - * Implement Request #16213: add alias to list-channels output [dufuz] -* Implement Request #16378: pear svntag [dufuz] -* Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj] -* Implement Request #16396: package-dependencies should allow package names [dufuz] -* Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz] -* Fix Bug #14493: pear install --offline doesn't print out errors [dufuz] -* Fix Bug #11348: pear package-dependencies isn't well explained [dufuz] -* Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz] -* Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz] -* Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz] -* Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz] -* Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj] -* Fix Bug #16444: Setting preferred mirror fails [dufuz] -* Fix the shutdown functions where a index might not exist and thus raise a notice [derick] - - - - 1.9.0RC2 - 2009-08-20 - New BSD License - beta - * REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz] - - - - 1.9.0RC3 - 2009-08-21 - New BSD License - beta - * Improved svntag support to handle packages like PEAR it self [dufuz] - - - - 1.9.0RC4 - 2009-08-23 - New BSD License - beta - * Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz] -* Make sure channel aliases can't be made to start with - [dufuz] -* Output issues with pear search [dufuz] -* Fixed couple of stray notices [dufuz] - - - - 1.9.0 - 2009-09-03 - New BSD License - stable - * Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] - - - - -package2.xml100644 1750 1750 14156 10560475634 6540 - - Structures_Graph - pear.php.net - Graph datastructure manipulation library - Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed -and undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing -as well as for characteristic extraction from the graph topology. - - Sérgio Carvalho - sergiosgc - sergio.carvalho@portugalmail.com - yes - - 2007-02-01 - - - 1.0.2 - 1.0.0 - - - stable - stable - - LGPL - - Bug #9682 only variables can be returned by reference -- fix Bug #9661 notice in Structures_Graph_Manipulator_Topological::sort() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4.2.0 - - - 1.4.3 - - - - - - - - 1.0.2 - 1.0.0 - - - stable - stable - - 2007-01-07 - LGPL - - Bug #9682 only variables can be returned by reference -- fix Bug #9661 notice in Structures_Graph_Manipulator_Topological::sort() - - - -Structures_Graph-1.0.2/docs/html/media/banner.css100644 1750 1750 651 10560475634 15166 body -{ - background-color: #CCCCFF; - margin: 0px; - padding: 0px; -} - -/* Banner (top bar) classes */ - -.banner { } - -.banner-menu -{ - clear: both; - padding: .5em; - border-top: 2px solid #6666AA; -} - -.banner-title -{ - text-align: right; - font-size: 20pt; - font-weight: bold; - margin: .2em; -} - -.package-selector -{ - background-color: #AAAADD; - border: 1px solid black; - color: yellow; -} -Structures_Graph-1.0.2/docs/html/media/stylesheet.css100644 1750 1750 12012 10560475634 16144 a { color: #336699; text-decoration: none; } -a:hover { color: #6699CC; text-decoration: underline; } -a:active { color: #6699CC; text-decoration: underline; } - -body { background : #FFFFFF; } -body, table { font-family: Georgia, Times New Roman, Times, serif; font-size: 10pt } -p, li { line-height: 140% } -a img { border: 0px; } -dd { margin-left: 0px; padding-left: 1em; } - -/* Page layout/boxes */ - -.info-box {} -.info-box-title { margin: 1em 0em 0em 0em; padding: .25em; font-weight: normal; font-size: 14pt; border: 2px solid #999999; background-color: #CCCCFF } -.info-box-body { border: 1px solid #999999; padding: .5em; } -.nav-bar { font-size: 8pt; white-space: nowrap; text-align: right; padding: .2em; margin: 0em 0em 1em 0em; } - -.oddrow { background-color: #F8F8F8; border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} -.evenrow { border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em} - -.page-body { max-width: 800px; margin: auto; } -.tree dl { margin: 0px } - -/* Index formatting classes */ - -.index-item-body { margin-top: .5em; margin-bottom: .5em} -.index-item-description { margin-top: .25em } -.index-item-details { font-weight: normal; font-style: italic; font-size: 8pt } -.index-letter-section { background-color: #EEEEEE; border: 1px dotted #999999; padding: .5em; margin-bottom: 1em} -.index-letter-title { font-size: 12pt; font-weight: bold } -.index-letter-menu { text-align: center; margin: 1em } -.index-letter { font-size: 12pt } - -/* Docbook classes */ - -.description {} -.short-description { font-weight: bold; color: #666666; } -.tags { padding-left: 0em; margin-left: 3em; color: #666666; list-style-type: square; } -.parameters { padding-left: 0em; margin-left: 3em; font-style: italic; list-style-type: square; } -.redefinitions { font-size: 8pt; padding-left: 0em; margin-left: 2em; } -.package { } -.package-title { font-weight: bold; font-size: 14pt; border-bottom: 1px solid black } -.package-details { font-size: 85%; } -.sub-package { font-weight: bold; font-size: 120% } -.tutorial { border-width: thin; border-color: #0066ff } -.tutorial-nav-box { width: 100%; border: 1px solid #999999; background-color: #F8F8F8; } -.nav-button-disabled { color: #999999; } -.nav-button:active, -.nav-button:focus, -.nav-button:hover { background-color: #DDDDDD; outline: 1px solid #999999; text-decoration: none } -.folder-title { font-style: italic } - -/* Generic formatting */ - -.field { font-weight: bold; } -.detail { font-size: 8pt; } -.notes { font-style: italic; font-size: 8pt; } -.separator { background-color: #999999; height: 2px; } -.warning { color: #FF6600; } -.disabled { font-style: italic; color: #999999; } - -/* Code elements */ - -.line-number { } - -.class-table { width: 100%; } -.class-table-header { border-bottom: 1px dotted #666666; text-align: left} -.class-name { color: #000000; font-weight: bold; } - -.method-summary { padding-left: 1em; font-size: 8pt } -.method-header { } -.method-definition { margin-bottom: .3em } -.method-title { font-weight: bold; } -.method-name { font-weight: bold; } -.method-signature { font-size: 85%; color: #666666; margin: .5em 0em } -.method-result { font-style: italic; } - -.var-summary { padding-left: 1em; font-size: 8pt; } -.var-header { } -.var-title { margin-bottom: .3em } -.var-type { font-style: italic; } -.var-name { font-weight: bold; } -.var-default {} -.var-description { font-weight: normal; color: #000000; } - -.include-title { } -.include-type { font-style: italic; } -.include-name { font-weight: bold; } - -.const-title { } -.const-name { font-weight: bold; } - -/* Syntax highlighting */ - -.src-code { border: 1px solid #336699; padding: 1em; background-color: #EEEEEE; } - -.src-comm { color: green; } -.src-id { } -.src-inc { color: #0000FF; } -.src-key { color: #0000FF; } -.src-num { color: #CC0000; } -.src-str { color: #66cccc; } -.src-sym { font-weight: bold; } -.src-var { } - -.src-php { font-weight: bold; } - -.src-doc { color: #009999 } -.src-doc-close-template { color: #0000FF } -.src-doc-coretag { color: #0099FF; font-weight: bold } -.src-doc-inlinetag { color: #0099FF } -.src-doc-internal { color: #6699cc } -.src-doc-tag { color: #0080CC } -.src-doc-template { color: #0000FF } -.src-doc-type { font-style: italic } -.src-doc-var { font-style: italic } - -/* tutorial */ - -.authors { } -.author { font-style: italic; font-weight: bold } -.author-blurb { margin: .5em 0em .5em 2em; font-size: 85%; font-weight: normal; font-style: normal } -.example { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em } -.listing { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; white-space: nowrap } -.release-info { font-size: 85%; font-style: italic; margin: 1em 0em } -.ref-title-box { } -.ref-title { } -.ref-purpose { font-style: italic; color: #666666 } -.ref-synopsis { } -.title { font-weight: bold; margin: 1em 0em 0em 0em; padding: .25em; border: 2px solid #999999; background-color: #CCCCFF } -.cmd-synopsis { margin: 1em 0em } -.cmd-title { font-weight: bold } -.toc { margin-left: 2em; padding-left: 0em } - -Structures_Graph-1.0.2/docs/html/Structures_Graph/Structures_Graph.html100644 1750 1750 21655 10560475634 21675 - - - - - Docs For Class Structures_Graph - - - - -
    -

    Class Structures_Graph

    - - -
    -
    Description
    - -
    - -

    The Structures_Graph class represents a graph data structure.

    -

    A Graph is a data structure composed by a set of nodes, connected by arcs. Graphs may either be directed or undirected. In a directed graph, arcs are directional, and can be traveled only one way. In an undirected graph, arcs are bidirectional, and can be traveled both ways.

    - -

    - Located in /Structures/Graph.php (line 56) -

    - - -
    
    -	
    -			
    -
    - - - - -
    -
    Method Summary
    - -
    -
    - -
    - Structures_Graph - Structures_Graph - ([boolean $directed = true]) -
    - -
    - void - addNode - (Structures_Graph_Node &$newNode) -
    - -
    - array - &getNodes - () -
    - -
    - boolean - isDirected - () -
    - -
    - void - removeNode - (Structures_Graph_Node &$node) -
    -
    -
    -
    - - - -
    -
    Methods
    - -
    - - -
    - -
    - Constructor Structures_Graph (line 76) -
    - - -

    Constructor

    -
      -
    • access: public
    • -
    - -
    - Structures_Graph - - Structures_Graph - - ([boolean $directed = true]) -
    - -
      -
    • - boolean - $directed: Set to true if the graph is directed. Set to false if it is not directed. (Optional, defaults to true)
    • -
    - - -
    - -
    - -
    - addNode (line 102) -
    - - -

    Add a Node to the Graph

    -
      -
    • access: public
    • -
    - -
    - void - - addNode - - (Structures_Graph_Node &$newNode) -
    - - - - -
    - -
    - -
    - getNodes (line 151) -
    - - -

    Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.

    - - -
    - array - - &getNodes - - () -
    - - - -
    - -
    - -
    - isDirected (line 89) -
    - - -

    Return true if a graph is directed

    -
      -
    • return: true if the graph is directed
    • -
    • access: public
    • -
    - -
    - boolean - - isDirected - - () -
    - - - -
    - -
    - -
    - removeNode (line 138) -
    - - -

    Remove a Node from the Graph

    -
      -
    • access: public
    • -
    • todo: This is unimplemented
    • -
    - -
    - void - - removeNode - - (Structures_Graph_Node &$node) -
    - - - - -
    - -
    -
    - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 -

    -
    -Structures_Graph-1.0.2/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html100644 1750 1750 7560 10560475634 26516 - - - - - Docs For Class Structures_Graph_Manipulator_AcyclicTest - - - - -
    -

    Class Structures_Graph_Manipulator_AcyclicTest

    - - -
    -
    Description
    - -
    - -

    The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle.

    -

    The definition of an acyclic graph used in this manipulator is that of a DAG. The graph must be directed, or else it is considered cyclic, even when there are no arcs.

    - -

    - Located in /Structures/Graph/Manipulator/AcyclicTest.php (line 55) -

    - - -
    
    -	
    -			
    -
    - - - - -
    -
    Method Summary
    - -
    -
    - -
    - boolean - isAcyclic - (mixed &$graph) -
    -
    -
    -
    - - - -
    -
    Methods
    - -
    - - -
    - -
    - isAcyclic (line 126) -
    - - -

    isAcyclic returns true if a graph contains no cycles, false otherwise.

    -
      -
    • return: true iff graph is acyclic
    • -
    • access: public
    • -
    - -
    - boolean - - isAcyclic - - (mixed &$graph) -
    - - - -
    - -
    -
    - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 -

    -
    -././@LongLink000 145 0 4476 LStructures_Graph-1.0.2/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.htmlStructures_Graph-1.0.2/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.htm100644 1750 1750 10313 10560475634 27614 - - - - - Docs For Class Structures_Graph_Manipulator_TopologicalSorter - - - - -
    -

    Class Structures_Graph_Manipulator_TopologicalSorter

    - - -
    -
    Description
    - -
    - -

    The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order.

    -

    A graph may only be sorted topologically iff it's a DAG. You can test it with the Structures_Graph_Manipulator_AcyclicTest.

    - -

    - Located in /Structures/Graph/Manipulator/TopologicalSorter.php (line 58) -

    - - -
    
    -	
    -			
    -
    - - - - -
    -
    Method Summary
    - -
    -
    - -
    - array - sort - (mixed &$graph) -
    -
    -
    -
    - - - -
    -
    Methods
    - -
    - - -
    - -
    - sort (line 133) -
    - - -

    sort returns the graph's nodes, sorted by topological order.

    -

    The result is an array with as many entries as topological levels. Each entry in this array is an array of nodes within the given topological level.

    -
      -
    • return: The graph's nodes, sorted by topological order.
    • -
    • access: public
    • -
    - -
    - array - - sort - - (mixed &$graph) -
    - - - -
    - -
    -
    - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 -

    -
    -Structures_Graph-1.0.2/docs/html/Structures_Graph/Structures_Graph_Node.html100644 1750 1750 51135 10560475634 22636 - - - - - Docs For Class Structures_Graph_Node - - - - -
    -

    Class Structures_Graph_Node

    - - -
    -
    Description
    - -
    - -

    The Structures_Graph_Node class represents a Node that can be member of a graph node set.

    -

    A graph node can contain data. Under this API, the node contains default data, and key index data. It behaves, thus, both as a regular data node, and as a dictionary (or associative array) node.

    Regular data is accessed via getData and setData. Key indexed data is accessed via getMetadata and setMetadata.

    - -

    - Located in /Structures/Graph/Node.php (line 57) -

    - - -
    
    -	
    -			
    -
    - - - - -
    -
    Method Summary
    - -
    -
    - -
    - Structures_Graph_Node - Structures_Graph_Node - () -
    - -
    - boolean - connectsTo - (mixed &$target) -
    - -
    - void - connectTo - (Structures_Graph &$destinationNode) -
    - -
    - mixed - &getData - () -
    - - - -
    - mixed - &getMetadata - (string $key, [boolean $nullIfNonexistent = false]) -
    - -
    - array - getNeighbours - () -
    - -
    - integer - inDegree - () -
    - -
    - boolean - metadataKeyExists - (string $key) -
    - -
    - integer - outDegree - () -
    - -
    - mixed - setData - (mixed $data) -
    - -
    - void - setGraph - (Structures_Graph &$graph) -
    - -
    - void - setMetadata - (string $key, mixed $data) -
    - -
    - void - unsetMetadata - (string $key) -
    -
    -
    -
    - - - -
    -
    Methods
    - -
    - - -
    - -
    - Constructor Structures_Graph_Node (line 78) -
    - - -

    Constructor

    -
      -
    • access: public
    • -
    - -
    - Structures_Graph_Node - - Structures_Graph_Node - - () -
    - - - -
    - -
    - -
    - connectsTo (line 275) -
    - - -

    Test wether this node has an arc to the target node

    -
      -
    • return: True if the two nodes are connected
    • -
    • access: public
    • -
    - -
    - boolean - - connectsTo - - (mixed &$target) -
    - - - -
    - -
    - -
    - connectTo (line 236) -
    - - -

    Connect this node to another one.

    -

    If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.

    -
      -
    • access: public
    • -
    - -
    - void - - connectTo - - (Structures_Graph &$destinationNode) -
    - - - - -
    - -
    - -
    - getData (line 119) -
    - - -

    Node data getter.

    -

    Each graph node can contain a reference to one variable. This is the getter for that reference.

    -
      -
    • return: Data stored in node
    • -
    • access: public
    • -
    - -
    - mixed - - &getData - - () -
    - - - -
    - -
    - -
    - getGraph (line 90) -
    - - -

    Node graph getter

    -
      -
    • return: Graph where node is stored
    • -
    • access: public
    • -
    - -
    - Structures_Graph - - &getGraph - - () -
    - - - -
    - -
    - -
    - getMetadata (line 171) -
    - - -

    Node metadata getter

    -

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method gets the data under the given key. If the key does not exist, an error will be thrown, so testing using metadataKeyExists might be needed.

    - - -
    - mixed - - &getMetadata - - (string $key, [boolean $nullIfNonexistent = false]) -
    - -
      -
    • - string - $key: Key
    • -
    • - boolean - $nullIfNonexistent: nullIfNonexistent (defaults to false).
    • -
    - - -
    - -
    - -
    - getNeighbours (line 262) -
    - - -

    Return nodes connected to this one.

    -
      -
    • return: Array of nodes
    • -
    • access: public
    • -
    - -
    - array - - getNeighbours - - () -
    - - - -
    - -
    - -
    - inDegree (line 309) -
    - - -

    Calculate the in degree of the node.

    -

    The indegree for a node is the number of arcs entering the node. For non directed graphs, the indegree is equal to the outdegree.

    -
      -
    • return: In degree of the node
    • -
    • access: public
    • -
    - -
    - integer - - inDegree - - () -
    - - - -
    - -
    - -
    - metadataKeyExists (line 151) -
    - - -

    Test for existence of metadata under a given key.

    -

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method tests whether a given metadata key exists for this node.

    -
      -
    • access: public
    • -
    - -
    - boolean - - metadataKeyExists - - (string $key) -
    - -
      -
    • - string - $key: Key to test
    • -
    - - -
    - -
    - -
    - outDegree (line 333) -
    - - -

    Calculate the out degree of the node.

    -

    The outdegree for a node is the number of arcs exiting the node. For non directed graphs, the outdegree is always equal to the indegree.

    -
      -
    • return: Out degree of the node
    • -
    • access: public
    • -
    - -
    - integer - - outDegree - - () -
    - - - -
    - -
    - -
    - setData (line 134) -
    - - -

    Node data setter

    -

    Each graph node can contain a reference to one variable. This is the setter for that reference.

    -
      -
    • return: Data to store in node
    • -
    • access: public
    • -
    - -
    - mixed - - setData - - (mixed $data) -
    - - - -
    - -
    - -
    - setGraph (line 104) -
    - - -

    Node graph setter. This method should not be called directly. Use Graph::addNode instead.

    - - -
    - void - - setGraph - - (Structures_Graph &$graph) -
    - - - - -
    - -
    - -
    - setMetadata (line 214) -
    - - -

    Node metadata setter

    -

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method stores data under the given key. If the key already exists, previously stored data is discarded.

    -
      -
    • access: public
    • -
    - -
    - void - - setMetadata - - (string $key, mixed $data) -
    - -
      -
    • - string - $key: Key
    • -
    • - mixed - $data: Data
    • -
    - - -
    - -
    - -
    - unsetMetadata (line 196) -
    - - -

    Delete metadata by key

    -

    Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an associative array or in a dictionary. This method removes any data that might be stored under the provided key. If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence.

    -
      -
    • access: public
    • -
    - -
    - void - - unsetMetadata - - (string $key) -
    - -
      -
    • - string - $key: Key
    • -
    - - -
    - -
    -
    - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 -

    -
    -Structures_Graph-1.0.2/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html100644 1750 1750 11131 10560475634 24364 - - - - - Structures_Graph Tutorial - - - - -
    - -

    Structures_Graph Tutorial

    -

    A first tour of graph datastructure manipulation

    -

    Introduction

    Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed.

    -

    Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph.

    -

    Creating a Graph

    Creating a graph is done using the simple constructor: -

    -require_once 'Structures/Graph.php';
    -
    -$directedGraph =& new Structures_Graph(true);
    -$nonDirectedGraph =& new Structures_Graph(false);
    -    
    - and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic.

    -

    To fill out the graph, we'll need to create some nodes, and then call Graph::addNode. -

    -require_once 'Structures/Graph/Node.php';
    -
    -$nodeOne =& new Structures_Graph_Node();
    -$nodeTwo =& new Structures_Graph_Node();
    -$nodeThree =& new Structures_Graph_Node();
    -
    -$directedGraph->addNode(&$nodeOne);
    -$directedGraph->addNode(&$nodeTwo);
    -$directedGraph->addNode(&$nodeThree);
    -    
    - and then setup the arcs: -
    -$nodeOne->connectTo($nodeTwo);
    -$nodeOne->connectTo($nodeThree);
    -    
    - Note that arcs can only be created after the nodes have been inserted into the graph.

    -

    Associating Data

    Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data. -

    -$nodeOne->setData("Node One's Data is a String");
    -$nodeTwo->setData(1976);
    -$nodeThree->setData('Some other string');
    -
    -print("NodeTwo's Data is an integer: " . $nodeTwo->getData());
    -    

    -

    Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation: -

    -$nodeOne->setMetadata('example key', "Node One's Sample Metadata");
    -print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key'));
    -$nodeOne->unsetMetadata('example key');
    -    

    -

    Querying a Graph

    Structures_Graph provides for basic querying of the graph: -

    -// Nodes are able to calculate their indegree and outdegree
    -print("NodeOne's inDegree: " . $nodeOne->inDegree());
    -print("NodeOne's outDegree: " . $nodeOne->outDegree());
    -
    -// and naturally, nodes can report on their arcs
    -$arcs = $nodeOne->getNeighbours();
    -for ($i=0;$i<sizeof($arcs);$i++) {
    -    print("NodeOne has an arc to " . $arcs[$i]->getData());
    -}
    -    

    - - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 -

    -
    -././@LongLink000 144 0 4475 LStructures_Graph-1.0.2/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.htmlStructures_Graph-1.0.2/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html100644 1750 1750 7650 10560475634 27524 - - - - - Docs for page AcyclicTest.php - - - - -
    -

    /Structures/Graph/Manipulator/AcyclicTest.php

    - - -
    -
    Description
    - -
    - -

    This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator.

    - - -
    -
    - - -
    -
    Classes
    - -
    - - - - - - - - - -
    ClassDescription
    - Structures_Graph_Manipulator_AcyclicTest - - The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle. -
    -
    -
    - - -
    -
    Includes
    - -
    - -
    - -
    - - require_once - ('PEAR.php') - (line 35) - -
    - - - -
    - -
    - -
    - - require_once - ('Structures/Graph.php') - (line 37) - -
    - - - -
    - -
    - -
    - - require_once - ('Structures/Graph/Node.php') - (line 39) - -
    - - - -
    -
    -
    - - - - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 -

    -
    -././@LongLink000 152 0 4474 LStructures_Graph-1.0.2/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.htmlStructures_Graph-1.0.2/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_ph100644 1750 1750 10731 10560475634 27657 - - - - - Docs for page TopologicalSorter.php - - - - -
    -

    /Structures/Graph/Manipulator/TopologicalSorter.php

    - - -
    -
    Description
    - -
    - -

    This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class.

    - - -
    -
    - - -
    -
    Classes
    - -
    - - - - - - - - - -
    ClassDescription
    - Structures_Graph_Manipulator_TopologicalSorter - - The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order. -
    -
    -
    - - -
    -
    Includes
    - -
    - -
    - -
    - - require_once - ('PEAR.php') - (line 35) - -
    - - - -
    - -
    - -
    - - require_once - ('Structures/Graph.php') - (line 37) - -
    - - - -
    - -
    - -
    - - require_once - ('Structures/Graph/Node.php') - (line 39) - -
    - - - -
    - -
    - -
    - - require_once - ('Structures/Graph/Manipulator/AcyclicTest.php') - (line 41) - -
    - - - -
    -
    -
    - - - - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 -

    -
    -Structures_Graph-1.0.2/docs/html/Structures_Graph/_Structures_Graph_Node_php.html100644 1750 1750 6526 10560475634 23630 - - - - - Docs for page Node.php - - - - -
    -

    /Structures/Graph/Node.php

    - - -
    -
    Description
    - -
    - -

    This file contains the definition of the Structures_Graph_Node class

    - - -
    -
    - - -
    -
    Classes
    - -
    - - - - - - - - - -
    ClassDescription
    - Structures_Graph_Node - - The Structures_Graph_Node class represents a Node that can be member of a graph node set. -
    -
    -
    - - -
    -
    Includes
    - -
    - -
    - -
    - - require_once - ('PEAR.php') - (line 35) - -
    - - - -
    - -
    - -
    - - require_once - ('Structures/Graph.php') - (line 37) - -
    - - - -
    -
    -
    - - - - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 -

    -
    -Structures_Graph-1.0.2/docs/html/Structures_Graph/_Structures_Graph_php.html100644 1750 1750 10416 10560475634 22674 - - - - - Docs for page Graph.php - - - - -
    -

    /Structures/Graph.php

    - - -
    -
    Description
    - -
    - -

    The Graph.php file contains the definition of the Structures_Graph class

    - - -
    -
    - - -
    -
    Classes
    - -
    - - - - - - - - - -
    ClassDescription
    - Structures_Graph - - The Structures_Graph class represents a graph data structure. -
    -
    -
    - - -
    -
    Includes
    - -
    - -
    - -
    - - require_once - ('Structures/Graph/Node.php') - (line 37) - -
    - - -

    Graph Node

    - -
    - -
    - -
    - - require_once - ('PEAR.php') - (line 35) - -
    - - -

    PEAR base classes

    - -
    -
    -
    - - -
    -
    Constants
    - -
    - -
    - -
    - - STRUCTURES_GRAPH_ERROR_GENERIC = 100 - (line 40) - -
    - - - - -
    -
    -
    - - - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 -

    -
    -Structures_Graph-1.0.2/docs/html/classtrees_Structures_Graph.html100644 1750 1750 2563 10560475634 20576 - - - - - - - - - - - -

    - -

    -

    Root class Structures_Graph

    - - -

    Root class Structures_Graph_Manipulator_AcyclicTest

    - - -

    Root class Structures_Graph_Manipulator_TopologicalSorter

    - - -

    Root class Structures_Graph_Node

    - - -

    - Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by phpDocumentor 1.2.3 -

    - -Structures_Graph-1.0.2/docs/html/elementindex.html100644 1750 1750 37131 10560475634 15542 - - - - - - - - - - -

    Full index

    -

    Package indexes

    - -
    -
    - a - c - g - i - m - n - o - r - s - t - u -
    - - -
    -
    a
    - -
    -
    -
    -
    - addNode -
    -
    - -
    Add a Node to the Graph
    -
    -
    - AcyclicTest.php -
    -
    -
    AcyclicTest.php in AcyclicTest.php
    -
    -
    - -
    -
    c
    - -
    -
    -
    -
    - connectsTo -
    -
    - -
    Test wether this node has an arc to the target node
    -
    -
    - connectTo -
    -
    - -
    Connect this node to another one.
    -
    -
    - -
    -
    g
    - -
    -
    -
    -
    - getData -
    -
    - -
    Node data getter.
    -
    -
    - getGraph -
    -
    - -
    Node graph getter
    -
    -
    - getMetadata -
    -
    - -
    Node metadata getter
    -
    -
    - getNeighbours -
    -
    - -
    Return nodes connected to this one.
    -
    -
    - getNodes -
    -
    - -
    Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.
    -
    -
    - Graph.php -
    -
    -
    Graph.php in Graph.php
    -
    -
    - -
    -
    i
    - -
    -
    -
    -
    - inDegree -
    -
    - -
    Calculate the in degree of the node.
    -
    -
    - isAcyclic -
    -
    - -
    isAcyclic returns true if a graph contains no cycles, false otherwise.
    -
    -
    - isDirected -
    -
    - -
    Return true if a graph is directed
    -
    -
    - -
    -
    m
    - -
    -
    -
    -
    - metadataKeyExists -
    -
    - -
    Test for existence of metadata under a given key.
    -
    -
    - -
    -
    n
    - -
    -
    -
    -
    - Node.php -
    -
    -
    Node.php in Node.php
    -
    -
    - -
    -
    o
    - -
    -
    -
    -
    - outDegree -
    -
    - -
    Calculate the out degree of the node.
    -
    -
    - -
    -
    r
    - -
    -
    -
    -
    - removeNode -
    -
    - -
    Remove a Node from the Graph
    -
    -
    - -
    -
    s
    - -
    -
    -
    -
    - setData -
    -
    - -
    Node data setter
    -
    -
    - setGraph -
    -
    - -
    Node graph setter. This method should not be called directly. Use Graph::addNode instead.
    -
    -
    - setMetadata -
    -
    - -
    Node metadata setter
    -
    -
    - sort -
    -
    - -
    sort returns the graph's nodes, sorted by topological order.
    -
    -
    - Structures_Graph -
    -
    -
    Structures_Graph in Graph.php
    -
    The Structures_Graph class represents a graph data structure.
    -
    -
    - Structures_Graph -
    -
    - -
    Constructor
    -
    -
    - STRUCTURES_GRAPH_ERROR_GENERIC -
    -
    - -
    -
    - Structures_Graph_Manipulator_AcyclicTest -
    -
    - -
    The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle.
    -
    -
    - Structures_Graph_Manipulator_TopologicalSorter -
    -
    - -
    The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order.
    -
    -
    - Structures_Graph_Node -
    -
    - -
    Constructor
    -
    -
    - Structures_Graph_Node -
    -
    - -
    The Structures_Graph_Node class represents a Node that can be member of a graph node set.
    -
    -
    - -
    -
    t
    - -
    -
    -
    -
    - TopologicalSorter.php -
    -
    -
    TopologicalSorter.php in TopologicalSorter.php
    -
    -
    - -
    -
    u
    - -
    -
    -
    -
    - unsetMetadata -
    -
    - -
    Delete metadata by key
    -
    -
    - -
    - a - c - g - i - m - n - o - r - s - t - u -
    -Structures_Graph-1.0.2/docs/html/elementindex_Structures_Graph.html100644 1750 1750 37637 10560475634 21141 - - - - - - - - - - -

    [Structures_Graph] element index

    -All elements -
    -
    - a - c - g - i - m - n - o - r - s - t - u -
    - - -
    -
    a
    - -
    -
    -
    -
    - addNode -
    -
    - -
    Add a Node to the Graph
    -
    -
    - AcyclicTest.php -
    -
    -
    AcyclicTest.php in AcyclicTest.php
    -
    -
    - -
    -
    c
    - -
    -
    -
    -
    - connectsTo -
    -
    - -
    Test wether this node has an arc to the target node
    -
    -
    - connectTo -
    -
    - -
    Connect this node to another one.
    -
    -
    - -
    -
    g
    - -
    -
    -
    -
    - getData -
    -
    - -
    Node data getter.
    -
    -
    - getGraph -
    -
    - -
    Node graph getter
    -
    -
    - getMetadata -
    -
    - -
    Node metadata getter
    -
    -
    - getNeighbours -
    -
    - -
    Return nodes connected to this one.
    -
    -
    - getNodes -
    -
    - -
    Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.
    -
    -
    - Graph.php -
    -
    -
    Graph.php in Graph.php
    -
    -
    - -
    -
    i
    - -
    -
    -
    -
    - inDegree -
    -
    - -
    Calculate the in degree of the node.
    -
    -
    - isAcyclic -
    -
    - -
    isAcyclic returns true if a graph contains no cycles, false otherwise.
    -
    -
    - isDirected -
    -
    - -
    Return true if a graph is directed
    -
    -
    - -
    -
    m
    - -
    -
    -
    -
    - metadataKeyExists -
    -
    - -
    Test for existence of metadata under a given key.
    -
    -
    - -
    -
    n
    - -
    -
    -
    -
    - Node.php -
    -
    -
    Node.php in Node.php
    -
    -
    - -
    -
    o
    - -
    -
    -
    -
    - outDegree -
    -
    - -
    Calculate the out degree of the node.
    -
    -
    - -
    -
    r
    - -
    -
    -
    -
    - removeNode -
    -
    - -
    Remove a Node from the Graph
    -
    -
    - -
    -
    s
    - -
    -
    -
    -
    - setData -
    -
    - -
    Node data setter
    -
    -
    - setGraph -
    -
    - -
    Node graph setter. This method should not be called directly. Use Graph::addNode instead.
    -
    -
    - setMetadata -
    -
    - -
    Node metadata setter
    -
    -
    - sort -
    -
    - -
    sort returns the graph's nodes, sorted by topological order.
    -
    -
    - Structures_Graph -
    -
    -
    Structures_Graph in Graph.php
    -
    The Structures_Graph class represents a graph data structure.
    -
    -
    - Structures_Graph -
    -
    - -
    Constructor
    -
    -
    - STRUCTURES_GRAPH_ERROR_GENERIC -
    -
    - -
    -
    - Structures_Graph_Manipulator_AcyclicTest -
    -
    - -
    The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator which tests whether a graph contains a cycle.
    -
    -
    - Structures_Graph_Manipulator_TopologicalSorter -
    -
    - -
    The Structures_Graph_Manipulator_TopologicalSorter is a manipulator which is able to return the set of nodes in a graph, sorted by topological order.
    -
    -
    - Structures_Graph_Node -
    -
    - -
    Constructor
    -
    -
    - Structures_Graph_Node -
    -
    - -
    The Structures_Graph_Node class represents a Node that can be member of a graph node set.
    -
    -
    - -
    -
    t
    - -
    -
    -
    -
    - TopologicalSorter.php -
    -
    -
    TopologicalSorter.php in TopologicalSorter.php
    -
    -
    - -
    -
    u
    - -
    -
    -
    -
    - unsetMetadata -
    -
    - -
    Delete metadata by key
    -
    -
    - -
    - a - c - g - i - m - n - o - r - s - t - u -
    -Structures_Graph-1.0.2/docs/html/errors.html100644 1750 1750 1344 10560475634 14352 - - - - - phpDocumentor Parser Errors and Warnings - - - - - Post-parsing
    -

    - Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 -

    - -Structures_Graph-1.0.2/docs/html/index.html100644 1750 1750 2010 10560475634 14134 - - - - - Structures_Graph Documentation - - - - - - - - - - - <H2>Frame Alert</H2> - <P>This document is designed to be viewed using the frames feature. - If you see this message, you are using a non-frame-capable web client.</P> - - -Structures_Graph-1.0.2/docs/html/li_Structures_Graph.html100644 1750 1750 5044 10560475634 17027 - - - - - - - - - -
    Structures_Graph
    - -

    phpDocumentor v 1.2.3

    - -Structures_Graph-1.0.2/docs/html/packages.html100644 1750 1750 1673 10560475634 14621 - - - - - - - - - - - - - Structures_Graph-1.0.2/docs/html/todolist.html100644 1750 1750 1600 10560475634 14672 - - - - - Todo List - - - - -

    Todo List

    -

    Structures_Graph

    -

    Structures_Graph::removeNode()

    -
      -
    • This is unimplemented
    • -
    -

    - Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by phpDocumentor 1.2.3 -

    - -Structures_Graph-1.0.2/docs/tutorials/Structures_Graph/Structures_Graph.pkg100644 1750 1750 7714 10560475634 22554 - - Structures_Graph Tutorial - A first tour of graph datastructure manipulation - - - Introduction - - Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed. - - - Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph. - - - - Creating a Graph - - Creating a graph is done using the simple constructor: - - - - and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic. - - - To fill out the graph, we'll need to create some nodes, and then call Graph::addNode. - - addNode(&$nodeOne); -$directedGraph->addNode(&$nodeTwo); -$directedGraph->addNode(&$nodeThree); - ]]> - - and then setup the arcs: - - connectTo($nodeTwo); -$nodeOne->connectTo($nodeThree); - ]]> - - Note that arcs can only be created after the nodes have been inserted into the graph. - - - - Associating Data - - Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data. - - setData("Node One's Data is a String"); -$nodeTwo->setData(1976); -$nodeThree->setData('Some other string'); - -print("NodeTwo's Data is an integer: " . $nodeTwo->getData()); - ]]> - - - - Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation: - - setMetadata('example key', "Node One's Sample Metadata"); -print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key')); -$nodeOne->unsetMetadata('example key'); - ]]> - - - - - Querying a Graph - - Structures_Graph provides for basic querying of the graph: - - inDegree()); -print("NodeOne's outDegree: " . $nodeOne->outDegree()); - -// and naturally, nodes can report on their arcs -$arcs = $nodeOne->getNeighbours(); -for ($i=0;$igetData()); -} - ]]> - - - - -Structures_Graph-1.0.2/docs/generate.sh100644 1750 1750 555 10560475634 13315 #!/bin/sh -(cd ..; tar czf docs/arch.tgz "{arch}") -rm -Rf "../{arch}" -rm -Rf ./html -mkdir -p ./html -phpdoc --directory ../Structures,./tutorials --target ./html --title "Structures_Graph Documentation" --output "HTML:frames" --defaultpackagename structures_graph --defaultcategoryname structures --pear -(cd ..; tar --absolute-names -xzf docs/arch.tgz) -#rm arch.tgz -Structures_Graph-1.0.2/Structures/Graph/Manipulator/AcyclicTest.php100644 1750 1750 13160 10560475634 20732 | -// +-----------------------------------------------------------------------------+ -// -/** - * This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator. - * - * @see Structures_Graph_Manipulator_AcyclicTest - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** */ -require_once 'PEAR.php'; -/** */ -require_once 'Structures/Graph.php'; -/** */ -require_once 'Structures/Graph/Node.php'; -/* }}} */ - -/* class Structures_Graph_Manipulator_AcyclicTest {{{ */ -/** - * The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator - * which tests whether a graph contains a cycle. - * - * The definition of an acyclic graph used in this manipulator is that of a - * DAG. The graph must be directed, or else it is considered cyclic, even when - * there are no arcs. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @package Structures_Graph - */ -class Structures_Graph_Manipulator_AcyclicTest { - /* _nonVisitedInDegree {{{ */ - /** - * - * This is a variant of Structures_Graph::inDegree which does - * not count nodes marked as visited. - * - * @access private - * @return integer Number of non-visited nodes that link to this one - */ - function _nonVisitedInDegree(&$node) { - $result = 0; - $graphNodes =& $node->_graph->getNodes(); - foreach (array_keys($graphNodes) as $key) { - if ((!$graphNodes[$key]->getMetadata('acyclic-test-visited')) && $graphNodes[$key]->connectsTo($node)) $result++; - } - return $result; - - } - /* }}} */ - - /* _isAcyclic {{{ */ - /** - * @access private - */ - function _isAcyclic(&$graph) { - // Mark every node as not visited - $nodes =& $graph->getNodes(); - $nodeKeys = array_keys($nodes); - $refGenerator = array(); - foreach($nodeKeys as $key) { - $refGenerator[] = false; - $nodes[$key]->setMetadata('acyclic-test-visited', $refGenerator[sizeof($refGenerator) - 1]); - } - - // Iteratively peel off leaf nodes - do { - // Find out which nodes are leafs (excluding visited nodes) - $leafNodes = array(); - foreach($nodeKeys as $key) { - if ((!$nodes[$key]->getMetadata('acyclic-test-visited')) && Structures_Graph_Manipulator_AcyclicTest::_nonVisitedInDegree($nodes[$key]) == 0) { - $leafNodes[] =& $nodes[$key]; - } - } - // Mark leafs as visited - for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) { - $visited =& $leafNodes[$i]->getMetadata('acyclic-test-visited'); - $visited = true; - $leafNodes[$i]->setMetadata('acyclic-test-visited', $visited); - } - } while (sizeof($leafNodes) > 0); - - // If graph is a DAG, there should be no non-visited nodes. Let's try to prove otherwise - $result = true; - foreach($nodeKeys as $key) if (!$nodes[$key]->getMetadata('acyclic-test-visited')) $result = false; - - // Cleanup visited marks - foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('acyclic-test-visited'); - - return $result; - } - /* }}} */ - - /* isAcyclic {{{ */ - /** - * - * isAcyclic returns true if a graph contains no cycles, false otherwise. - * - * @return boolean true iff graph is acyclic - * @access public - */ - function isAcyclic(&$graph) { - // We only test graphs - if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_AcyclicTest::isAcyclic received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC); - if (!$graph->isDirected()) return false; // Only directed graphs may be acyclic - - return Structures_Graph_Manipulator_AcyclicTest::_isAcyclic($graph); - } - /* }}} */ -} -/* }}} */ -?> -Structures_Graph-1.0.2/Structures/Graph/Manipulator/TopologicalSorter.php100644 1750 1750 15046 10560475634 22203 | -// +-----------------------------------------------------------------------------+ -// -/** - * This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class. - * - * @see Structures_Graph_Manipulator_TopologicalSorter - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** */ -require_once 'PEAR.php'; -/** */ -require_once 'Structures/Graph.php'; -/** */ -require_once 'Structures/Graph/Node.php'; -/** */ -require_once 'Structures/Graph/Manipulator/AcyclicTest.php'; -/* }}} */ - -/* class Structures_Graph_Manipulator_TopologicalSorter {{{ */ -/** - * The Structures_Graph_Manipulator_TopologicalSorter is a manipulator - * which is able to return the set of nodes in a graph, sorted by topological - * order. - * - * A graph may only be sorted topologically iff it's a DAG. You can test it - * with the Structures_Graph_Manipulator_AcyclicTest. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @see Structures_Graph_Manipulator_AcyclicTest - * @package Structures_Graph - */ -class Structures_Graph_Manipulator_TopologicalSorter { - /* _nonVisitedInDegree {{{ */ - /** - * - * This is a variant of Structures_Graph::inDegree which does - * not count nodes marked as visited. - * - * @access private - * @return integer Number of non-visited nodes that link to this one - */ - function _nonVisitedInDegree(&$node) { - $result = 0; - $graphNodes =& $node->_graph->getNodes(); - foreach (array_keys($graphNodes) as $key) { - if ((!$graphNodes[$key]->getMetadata('topological-sort-visited')) && $graphNodes[$key]->connectsTo($node)) $result++; - } - return $result; - - } - /* }}} */ - - /* _sort {{{ */ - /** - * @access private - */ - function _sort(&$graph) { - // Mark every node as not visited - $nodes =& $graph->getNodes(); - $nodeKeys = array_keys($nodes); - $refGenerator = array(); - foreach($nodeKeys as $key) { - $refGenerator[] = false; - $nodes[$key]->setMetadata('topological-sort-visited', $refGenerator[sizeof($refGenerator) - 1]); - } - - // Iteratively peel off leaf nodes - $topologicalLevel = 0; - do { - // Find out which nodes are leafs (excluding visited nodes) - $leafNodes = array(); - foreach($nodeKeys as $key) { - if ((!$nodes[$key]->getMetadata('topological-sort-visited')) && Structures_Graph_Manipulator_TopologicalSorter::_nonVisitedInDegree($nodes[$key]) == 0) { - $leafNodes[] =& $nodes[$key]; - } - } - // Mark leafs as visited - $refGenerator[] = $topologicalLevel; - for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) { - $visited =& $leafNodes[$i]->getMetadata('topological-sort-visited'); - $visited = true; - $leafNodes[$i]->setMetadata('topological-sort-visited', $visited); - $leafNodes[$i]->setMetadata('topological-sort-level', $refGenerator[sizeof($refGenerator) - 1]); - } - $topologicalLevel++; - } while (sizeof($leafNodes) > 0); - - // Cleanup visited marks - foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('topological-sort-visited'); - } - /* }}} */ - - /* sort {{{ */ - /** - * - * sort returns the graph's nodes, sorted by topological order. - * - * The result is an array with - * as many entries as topological levels. Each entry in this array is an array of nodes within - * the given topological level. - * - * @return array The graph's nodes, sorted by topological order. - * @access public - */ - function sort(&$graph) { - // We only sort graphs - if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC); - if (!Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph)) return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an graph that has cycles', STRUCTURES_GRAPH_ERROR_GENERIC); - - Structures_Graph_Manipulator_TopologicalSorter::_sort($graph); - $result = array(); - - // Fill out result array - $nodes =& $graph->getNodes(); - $nodeKeys = array_keys($nodes); - foreach($nodeKeys as $key) { - if (!array_key_exists($nodes[$key]->getMetadata('topological-sort-level'), $result)) $result[$nodes[$key]->getMetadata('topological-sort-level')] = array(); - $result[$nodes[$key]->getMetadata('topological-sort-level')][] =& $nodes[$key]; - $nodes[$key]->unsetMetadata('topological-sort-level'); - } - - return $result; - } - /* }}} */ -} -/* }}} */ -?> -Structures_Graph-1.0.2/Structures/Graph/Node.php100644 1750 1750 25232 10560475634 15120 | -// +-----------------------------------------------------------------------------+ -// -/** - * This file contains the definition of the Structures_Graph_Node class - * - * @see Structures_Graph_Node - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** */ -require_once 'PEAR.php'; -/** */ -require_once 'Structures/Graph.php'; -/* }}} */ - -/* class Structures_Graph_Node {{{ */ -/** - * The Structures_Graph_Node class represents a Node that can be member of a - * graph node set. - * - * A graph node can contain data. Under this API, the node contains default data, - * and key index data. It behaves, thus, both as a regular data node, and as a - * dictionary (or associative array) node. - * - * Regular data is accessed via getData and setData. Key indexed data is accessed - * via getMetadata and setMetadata. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @package Structures_Graph - */ -/* }}} */ -class Structures_Graph_Node { - /* fields {{{ */ - /** - * @access private - */ - var $_data = null; - /** @access private */ - var $_metadata = array(); - /** @access private */ - var $_arcs = array(); - /** @access private */ - var $_graph = null; - /* }}} */ - - /* Constructor {{{ */ - /** - * - * Constructor - * - * @access public - */ - function Structures_Graph_Node() { - } - /* }}} */ - - /* getGraph {{{ */ - /** - * - * Node graph getter - * - * @return Structures_Graph Graph where node is stored - * @access public - */ - function &getGraph() { - return $this->_graph; - } - /* }}} */ - - /* setGraph {{{ */ - /** - * - * Node graph setter. This method should not be called directly. Use Graph::addNode instead. - * - * @param Structures_Graph Set the graph for this node. - * @see Structures_Graph::addNode() - * @access public - */ - function setGraph(&$graph) { - $this->_graph =& $graph; - } - /* }}} */ - - /* getData {{{ */ - /** - * - * Node data getter. - * - * Each graph node can contain a reference to one variable. This is the getter for that reference. - * - * @return mixed Data stored in node - * @access public - */ - function &getData() { - return $this->_data; - } - /* }}} */ - - /* setData {{{ */ - /** - * - * Node data setter - * - * Each graph node can contain a reference to one variable. This is the setter for that reference. - * - * @return mixed Data to store in node - * @access public - */ - function setData($data) { - $this->_data =& $data; - } - /* }}} */ - - /* metadataKeyExists {{{ */ - /** - * - * Test for existence of metadata under a given key. - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method tests whether a given metadata key exists for this node. - * - * @param string Key to test - * @return boolean - * @access public - */ - function metadataKeyExists($key) { - return array_key_exists($key, $this->_metadata); - } - /* }}} */ - - /* getMetadata {{{ */ - /** - * - * Node metadata getter - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method gets the data under the given key. If the key does - * not exist, an error will be thrown, so testing using metadataKeyExists might be needed. - * - * @param string Key - * @param boolean nullIfNonexistent (defaults to false). - * @return mixed Metadata Data stored in node under given key - * @see metadataKeyExists - * @access public - */ - function &getMetadata($key, $nullIfNonexistent = false) { - if (array_key_exists($key, $this->_metadata)) { - return $this->_metadata[$key]; - } else { - if ($nullIfNonexistent) { - $a = null; - return $a; - } else { - $a = Pear::raiseError('Structures_Graph_Node::getMetadata: Requested key does not exist', STRUCTURES_GRAPH_ERROR_GENERIC); - return $a; - } - } - } - /* }}} */ - - /* unsetMetadata {{{ */ - /** - * - * Delete metadata by key - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method removes any data that might be stored under the provided key. - * If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence. - * - * @param string Key - * @access public - */ - function unsetMetadata($key) { - if (array_key_exists($key, $this->_metadata)) unset($this->_metadata[$key]); - } - /* }}} */ - - /* setMetadata {{{ */ - /** - * - * Node metadata setter - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method stores data under the given key. If the key already exists, - * previously stored data is discarded. - * - * @param string Key - * @param mixed Data - * @access public - */ - function setMetadata($key, $data) { - $this->_metadata[$key] =& $data; - } - /* }}} */ - - /* _connectTo {{{ */ - /** @access private */ - function _connectTo(&$destinationNode) { - $this->_arcs[] =& $destinationNode; - } - /* }}} */ - - /* connectTo {{{ */ - /** - * - * Connect this node to another one. - * - * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created. - * - * @param Structures_Graph Node to connect to - * @access public - */ - function connectTo(&$destinationNode) { - // We only connect to nodes - if (!is_a($destinationNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph_Node::connectTo received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC); - // Nodes must already be in graphs to be connected - if ($this->_graph == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC); - if ($destinationNode->getGraph() == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect to a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC); - // Connect here - $this->_connectTo($destinationNode); - // If graph is undirected, connect back - if (!$this->_graph->isDirected()) { - $destinationNode->_connectTo($this); - } - } - /* }}} */ - - /* getNeighbours {{{ */ - /** - * - * Return nodes connected to this one. - * - * @return array Array of nodes - * @access public - */ - function getNeighbours() { - return $this->_arcs; - } - /* }}} */ - - /* connectsTo {{{ */ - /** - * - * Test wether this node has an arc to the target node - * - * @return boolean True if the two nodes are connected - * @access public - */ - function connectsTo(&$target) { - $copy = $target; - $arcKeys = array_keys($this->_arcs); - foreach($arcKeys as $key) { - /* ZE1 chokes on this expression: - if ($target === $arc) return true; - so, we'll use more convoluted stuff - */ - $arc =& $this->_arcs[$key]; - $target = true; - if ($arc === true) { - $target = false; - if ($arc === false) { - $target = $copy; - return true; - } - } - } - $target = $copy; - return false; - } - /* }}} */ - - /* inDegree {{{ */ - /** - * - * Calculate the in degree of the node. - * - * The indegree for a node is the number of arcs entering the node. For non directed graphs, - * the indegree is equal to the outdegree. - * - * @return integer In degree of the node - * @access public - */ - function inDegree() { - if ($this->_graph == null) return 0; - if (!$this->_graph->isDirected()) return $this->outDegree(); - $result = 0; - $graphNodes =& $this->_graph->getNodes(); - foreach (array_keys($graphNodes) as $key) { - if ($graphNodes[$key]->connectsTo($this)) $result++; - } - return $result; - - } - /* }}} */ - - /* outDegree {{{ */ - /** - * - * Calculate the out degree of the node. - * - * The outdegree for a node is the number of arcs exiting the node. For non directed graphs, - * the outdegree is always equal to the indegree. - * - * @return integer Out degree of the node - * @access public - */ - function outDegree() { - if ($this->_graph == null) return 0; - return sizeof($this->_arcs); - } - /* }}} */ -} -?> -Structures_Graph-1.0.2/Structures/Graph.php100644 1750 1750 13163 10560475634 14233 | -// +-----------------------------------------------------------------------------+ -// -/** - * The Graph.php file contains the definition of the Structures_Graph class - * - * @see Structures_Graph - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** PEAR base classes */ -require_once 'PEAR.php'; -/** Graph Node */ -require_once 'Structures/Graph/Node.php'; -/* }}} */ - -define('STRUCTURES_GRAPH_ERROR_GENERIC', 100); - -/* class Structures_Graph {{{ */ -/** - * The Structures_Graph class represents a graph data structure. - * - * A Graph is a data structure composed by a set of nodes, connected by arcs. - * Graphs may either be directed or undirected. In a directed graph, arcs are - * directional, and can be traveled only one way. In an undirected graph, arcs - * are bidirectional, and can be traveled both ways. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @package Structures_Graph - */ -/* }}} */ -class Structures_Graph { - /* fields {{{ */ - /** - * @access private - */ - var $_nodes = array(); - /** - * @access private - */ - var $_directed = false; - /* }}} */ - - /* Constructor {{{ */ - /** - * - * Constructor - * - * @param boolean Set to true if the graph is directed. Set to false if it is not directed. (Optional, defaults to true) - * @access public - */ - function Structures_Graph($directed = true) { - $this->_directed = $directed; - } - /* }}} */ - - /* isDirected {{{ */ - /** - * - * Return true if a graph is directed - * - * @return boolean true if the graph is directed - * @access public - */ - function isDirected() { - return (boolean) $this->_directed; - } - /* }}} */ - - /* addNode {{{ */ - /** - * - * Add a Node to the Graph - * - * @param Structures_Graph_Node The node to be added. - * @access public - */ - function addNode(&$newNode) { - // We only add nodes - if (!is_a($newNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph::addNode received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC); - // Graphs are node *sets*, so duplicates are forbidden. We allow nodes that are exactly equal, but disallow equal references. - foreach($this->_nodes as $key => $node) { - /* - ZE1 equality operators choke on the recursive cycle introduced by the _graph field in the Node object. - So, we'll check references the hard way (change $this->_nodes[$key] and check if the change reflects in - $node) - */ - $savedData = $this->_nodes[$key]; - $referenceIsEqualFlag = false; - $this->_nodes[$key] = true; - if ($node === true) { - $this->_nodes[$key] = false; - if ($node === false) $referenceIsEqualFlag = true; - } - $this->_nodes[$key] = $savedData; - if ($referenceIsEqualFlag) return Pear::raiseError('Structures_Graph::addNode received an object that is a duplicate for this dataset', STRUCTURES_GRAPH_ERROR_GENERIC); - } - $this->_nodes[] =& $newNode; - $newNode->setGraph($this); - } - /* }}} */ - - /* removeNode (unimplemented) {{{ */ - /** - * - * Remove a Node from the Graph - * - * @todo This is unimplemented - * @param Structures_Graph_Node The node to be removed from the graph - * @access public - */ - function removeNode(&$node) { - } - /* }}} */ - - /* getNodes {{{ */ - /** - * - * Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted. - * - * @access public - * @see Structures_Graph_Manipulator_TopologicalSorter - * @return array The set of nodes in this graph - */ - function &getNodes() { - return $this->_nodes; - } - /* }}} */ -} -?> -Structures_Graph-1.0.2/tests/testCase/BasicGraph.php100644 1750 1750 22050 10560475634 15722 | -// +-----------------------------------------------------------------------------+ -// - -require_once 'Structures/Graph.php'; -require_once 'PHPUnit.php'; - -/** - * @access private - */ -class BasicGraph extends PHPUnit_TestCase -{ - var $_graph = null; - - // constructor of the test suite - function StringTest($name) { - $this->PHPUnit_TestCase($name); - } - - function setUp() { - } - - function tearDown() { - } - - function test_create_graph() { - $this->_graph = new Structures_Graph(); - $this->assertTrue(is_a($this->_graph, 'Structures_Graph')); - } - - function test_add_node() { - $this->_graph = new Structures_Graph(); - $data = 1; - $node = new Structures_Graph_Node($data); - $this->_graph->addNode($node); - $node = new Structures_Graph_Node($data); - $this->_graph->addNode($node); - $node = new Structures_Graph_Node($data); - $this->_graph->addNode($node); - } - - function test_connect_node() { - $this->_graph = new Structures_Graph(); - $data = 1; - $node1 = new Structures_Graph_Node($data); - $node2 = new Structures_Graph_Node($data); - $this->_graph->addNode($node1); - $this->_graph->addNode($node2); - $node1->connectTo($node2); - - $node =& $this->_graph->getNodes(); - $node =& $node[0]; - $node = $node->getNeighbours(); - $node =& $node[0]; - /* - ZE1 == and === operators fail on $node,$node2 because of the recursion introduced - by the _graph field in the Node object. So, we'll use the stupid method for reference - testing - */ - $node = true; - $this->assertTrue($node2); - $node = false; - $this->assertFalse($node2); - } - - function test_data_references() { - $this->_graph = new Structures_Graph(); - $data = 1; - $node = new Structures_Graph_Node(); - $node->setData(&$data); - $this->_graph->addNode($node); - $data = 2; - $dataInNode =& $this->_graph->getNodes(); - $dataInNode =& $dataInNode[0]; - $dataInNode =& $dataInNode->getData(); - $this->assertTrue($data === $dataInNode); - } - - function test_metadata_references() { - $this->_graph = new Structures_Graph(); - $data = 1; - $node = new Structures_Graph_Node(); - $node->setMetadata('5', &$data); - $data = 2; - $dataInNode =& $node->getMetadata('5'); - $this->assertTrue($data === $dataInNode); - } - - function test_metadata_key_exists() { - $this->_graph = new Structures_Graph(); - $data = 1; - $node = new Structures_Graph_Node(); - $node->setMetadata('5', $data); - $this->assertTrue($node->metadataKeyExists('5')); - $this->assertFalse($node->metadataKeyExists('1')); - } - - function test_directed_degree() { - $this->_graph = new Structures_Graph(true); - $node = array(); - $node[] = new Structures_Graph_Node(); - $node[] = new Structures_Graph_Node(); - $node[] = new Structures_Graph_Node(); - $this->_graph->addNode($node[0]); - $this->_graph->addNode($node[1]); - $this->_graph->addNode($node[2]); - $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 0 arcs'); - $this->assertEquals(0, $node[1]->inDegree(), 'inDegree test failed for node 1 with 0 arcs'); - $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 0 arcs'); - $this->assertEquals(0, $node[0]->outDegree(), 'outDegree test failed for node 0 with 0 arcs'); - $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 0 arcs'); - $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 0 arcs'); - $node[0]->connectTo($node[1]); - $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 1 arc'); - $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 1 arc'); - $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 1 arc'); - $this->assertEquals(1, $node[0]->outDegree(), 'outDegree test failed for node 0 with 1 arc'); - $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 1 arc'); - $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 1 arc'); - $node[0]->connectTo($node[2]); - $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 2 arcs'); - $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 2 arcs'); - $this->assertEquals(1, $node[2]->inDegree(), 'inDegree test failed for node 2 with 2 arcs'); - $this->assertEquals(2, $node[0]->outDegree(), 'outDegree test failed for node 0 with 2 arcs'); - $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 2 arcs'); - $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 2 arcs'); - } - - function test_undirected_degree() { - $this->_graph = new Structures_Graph(false); - $node = array(); - $node[] = new Structures_Graph_Node(); - $node[] = new Structures_Graph_Node(); - $node[] = new Structures_Graph_Node(); - $this->_graph->addNode($node[0]); - $this->_graph->addNode($node[1]); - $this->_graph->addNode($node[2]); - $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 0 arcs'); - $this->assertEquals(0, $node[1]->inDegree(), 'inDegree test failed for node 1 with 0 arcs'); - $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 0 arcs'); - $this->assertEquals(0, $node[0]->outDegree(), 'outDegree test failed for node 0 with 0 arcs'); - $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 0 arcs'); - $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 0 arcs'); - $node[0]->connectTo($node[1]); - $this->assertEquals(1, $node[0]->inDegree(), 'inDegree test failed for node 0 with 1 arc'); - $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 1 arc'); - $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 1 arc'); - $this->assertEquals(1, $node[0]->outDegree(), 'outDegree test failed for node 0 with 1 arc'); - $this->assertEquals(1, $node[1]->outDegree(), 'outDegree test failed for node 1 with 1 arc'); - $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 1 arc'); - $node[0]->connectTo($node[2]); - $this->assertEquals(2, $node[0]->inDegree(), 'inDegree test failed for node 0 with 2 arcs'); - $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 2 arcs'); - $this->assertEquals(1, $node[2]->inDegree(), 'inDegree test failed for node 2 with 2 arcs'); - $this->assertEquals(2, $node[0]->outDegree(), 'outDegree test failed for node 0 with 2 arcs'); - $this->assertEquals(1, $node[1]->outDegree(), 'outDegree test failed for node 1 with 2 arcs'); - $this->assertEquals(1, $node[2]->outDegree(), 'outDegree test failed for node 2 with 2 arcs'); - } -} -?> -Structures_Graph-1.0.2/tests/all-tests.php100644 1750 1750 4373 10560475634 14044 #!/usr/bin/php - | -// +-----------------------------------------------------------------------------+ -// - -// Place development Structures_Graph ahead in the include_path -ini_set('include_path', realpath(dirname(__FILE__) . "/..") . ":.:" . ini_get('include_path')); - -require_once 'testCase/BasicGraph.php'; -require_once 'PHPUnit.php'; - -$suite = new PHPUnit_TestSuite(); -$suite->addTest(new PHPUnit_TestSuite('BasicGraph')); -$result = PHPUnit::run($suite); - -echo $result->toString(); -?> -Structures_Graph-1.0.2/tests/README100644 1750 1750 0 10560475634 12202 Structures_Graph-1.0.2/genpackage.xml.pl100644 1750 1750 642 10560475634 13455 #!/usr/bin/perl -while (<>) { - if (!/FILESGOHERE/) { - print $_; - } else { - open FILELIST,'find Structures -type f | grep -v .arch-ids |'; - while () { - $md5sum = `md5sum $_`; - chomp($md5sum); - $md5sum = substr $md5sum, 0, 32; -# $_ =~ s/\//\\\//g; - chomp($_); - print " \n"; - } - } -} -Structures_Graph-1.0.2/LICENSE100644 1750 1750 63476 10560475634 11317 GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - -Structures_Graph-1.0.2/package.sh100644 1750 1750 3027 10560475634 12203 #!/bin/bash -VERSION=`tla tree-version 2>&1 | sed "s/^.*\([0-9][0-9]*\.[0-9][0-9]*\)$/\1/g"` -TARGET_DIR=BUILD/ -TARGET_DIRS=`find Structures -type d | grep -v .arch-ids` -mkdir -p $TARGET_DIR -./genpackage.xml.pl > BUILD/package.xml << EOF - - - Structures_Graph - Graph datastructure manipulation library - LGPL - - Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed - and undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing - as well as for characteristic extraction from the graph topology. - - - - sergiosgc - Sérgio Carvalho - sergio.carvalho@portugalmail.com - lead - - - - - 1.0.3 - 2007-01-30 - stable - - Version 1.0.3 is functionally equivalent to 1.0.2, but released with a v1.0 package.xml to deal with bug #9965:installation problem - - -FILESGOHERE - - - - PEAR - - -EOF -for dir in $TARGET_DIRS -do - mkdir -p $TARGET_DIR/$dir - cp `find $dir -maxdepth 1 -type f | grep -v .arch-ids` $TARGET_DIR/$dir -done -cp LICENSE BUILD -(cd BUILD; pear package) -rm -Rf BUILD/package.xml BUILD/LICENSE BUILD/Structures - - -Structures_Graph-1.0.2/publish.sh100644 1750 1750 411 10560475634 12230 #!/bin/sh -./package.sh -scp BUILD/*.tgz root@sergiocarvalho.com:/home/httpd/vhosts/com/sergiocarvalho/pear-base/pear -(cd docs; ./generate.sh) -scp -r docs/html/* root@iluvatar.portugalmail.pt:/home/httpd/vhosts/com/sergiocarvalho/pear-base/pear/docs/Structures_Graph -package.xml100644 1750 1750 7334 10560475634 6436 - - - Structures_Graph - Graph datastructure manipulation library - Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed -and undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing -as well as for characteristic extraction from the graph topology. - - - - sergiosgc - Sérgio Carvalho - sergio.carvalho@portugalmail.com - lead - - - - 1.0.2 - 2007-02-01 - LGPL - stable - - Bug #9682 only variables can be returned by reference -- fix Bug #9661 notice in Structures_Graph_Manipulator_Topological::sort() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -package.xml100644 1750 1750 36035 11117075467 6455 - - XML_Util - pear.php.net - XML utility class - Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more. - - Chuck Burgess - ashnazg - ashnazg@php.net - yes - - - Stephan Schmidt - schst - schst@php-tools.net - no - - - Davey Shafik - davey - davey@php.net - no - - 2008-12-07 - - - 1.2.1 - 1.2.0 - - - stable - stable - - BSD License - Fixed Bug #14760: Bug in getDocTypeDeclaration() [ashnazg|fpospisil] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4.3.0 - - - 1.4.3 - - - pcre - - - - - - - - 1.2.1 - 1.2.0 - - - stable - stable - - 2008-12-07 - BSD License - Fixed Bug #14760: Bug in getDocTypeDeclaration() [ashnazg|fpospisil] - - - - 1.2.0 - 1.2.0 - - - stable - stable - - 2008-07-26 - BSD License - Changed license to New BSD License (Req #13826 [ashnazg]) -Added a test suite against all API methods [ashnazg] -Switch to package.xml v2 [ashnazg] -Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] -Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] -Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] --- (this fix differs from the one in v1.2.0a1) - - - - 1.2.0RC1 - 1.2.0 - - - beta - beta - - 2008-07-12 - BSD License - Changed license to New BSD License (Req #13826 [ashnazg]) -Added a test suite against all API methods [ashnazg] -Switch to package.xml v2 [ashnazg] -Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] -Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] -Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] --- (this fix differs from the one in v1.2.0a1) - - - - 1.2.0a2 - 1.2.0 - - - alpha - alpha - - 2008-05-22 - BSD License - Changed license to New BSD License (Req #13826 [ashnazg]) -Added a test suite against all API methods [ashnazg] -Switch to package.xml v2 [ashnazg] -Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry] -Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg] -Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry] --- (this fix differs from the one in v1.2.0a1) - - - - 1.2.0a1 - 1.2.0 - - - alpha - alpha - - 2008-05-04 - BSD License - Changed license to New BSD License (Req #13826 [ashnazg]) -Added a test suite against all API methods [ashnazg] -Switch to package.xml v2 [ashnazg] -Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|ja.doma] - - - - 1.1.4 - 1.1.4 - - - stable - stable - - 2006-12-16 - PHP License - - Fixed bug #9561: Not allowing underscores in middle of tags - - - - 1.1.2 - 1.1.2 - - - stable - stable - - 2006-12-01 - PHP License - - fixed bug #5419: isValidName() now checks for character classes -- implemented request #8196: added optional parameter to influence array sorting to createTag() createTagFromArray() and createStartElement() - - - - 1.1.1 - 1.1.1 - - - stable - stable - - 2004-12-23 - PHP License - - fixed bug in replaceEntities() and reverseEntities() in conjunction with XML_UTIL_ENTITIES_HTML -- createTag() and createTagFromArray() now accept XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML, XML_UTIL_ENTITIES_NONE and XML_UTIL_CDATA_SECTION as $replaceEntities parameter - - - - 1.1.0 - 1.1.0 - - - stable - stable - - 2004-11-19 - PHP License - - Added collapseEmptyTags (patch by Sebastian Bergmann and Thomas Duffey) - - - - 1.0.0 - 1.0.0 - - - stable - stable - - 2004-10-28 - PHP License - - Added reverseEntities() (request #2639) - - - - 0.6.1 - 0.6.1 - - - stable - stable - - 2004-10-28 - PHP License - - Added check for tag name (either as local part or qualified name) in createTagFromArray() (bug #1083) - - - - 0.6.0 - 0.6.0 - - - stable - stable - - 2004-06-07 - PHP License - - Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey) -- added optional parameter to replaceEntities() to define the set of entities to replace -- added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann) -- allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter) -- introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error - - - - 0.6.0beta1 - 0.6.0beta1 - - - beta - beta - - 2004-05-24 - PHP License - - Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey) -- added optional parameter to replaceEntities() to define the set of entities to replace -- added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann) -- allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter) -- introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error - - - - 0.5.2 - 0.5.2 - - - stable - stable - - 2003-11-22 - PHP License - now creates XHTML compliant empty tags (Davey), -minor whitespace fixes (Davey) - - - - 0.5.1 - 0.5.1 - - - stable - stable - - 2003-09-26 - PHP License - added default namespace parameter (optional) in splitQualifiedName() (requested by Sebastian Bergmann) - - - - 0.5 - 0.5 - - - stable - stable - - 2003-09-23 - PHP License - added support for multiline attributes in attributesToString(), createTag*() and createStartElement (requested by Yavor Shahpasov for XML_Serializer), -added createComment - - - - 0.4 - 0.4 - - - stable - stable - - 2003-09-21 - PHP License - added createCDataSection(), -added support for CData sections in createTag* methods, -fixed bug #23, -fixed bug in splitQualifiedName() - - - - 0.3 - 0.3 - - - stable - stable - - 2003-09-12 - PHP License - added createStartElement() and createEndElement() - - - - 0.2.1 - 0.2.1 - - - stable - stable - - 2003-09-05 - PHP License - fixed bug with zero as tag content in createTagFromArray and createTag - - - - 0.2 - 0.2 - - - stable - stable - - 2003-08-12 - PHP License - added XML_Util::getDocTypeDeclaration() - - - - 0.1.1 - 0.1.1 - - - stable - stable - - 2003-08-02 - PHP License - bugfix: removed bug in createTagFromArray - - - - 0.1 - 0.1 - - - stable - stable - - 2003-08-01 - PHP License - inital release - - - -XML_Util-1.2.1/examples/example.php100644 1750 1750 21775 11117075466 12420 - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category XML - * @package XML_Util - * @subpackage Examples - * @author Stephan Schmidt - * @copyright 2003-2008 Stephan Schmidt - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: example.php,v 1.17 2008/05/05 19:05:28 ashnazg Exp $ - * @link http://pear.php.net/package/XML_Util - */ - - /** - * set error level - */ - error_reporting(E_ALL); - - require_once 'XML/Util.php'; - - /** - * replacing XML entities - */ - print 'replace XML entities:
    '; - print XML_Util::replaceEntities('This string contains < & >.'); - print "\n

    \n"; - - /** - * reversing XML entities - */ - print 'replace XML entities:
    '; - print XML_Util::reverseEntities('This string contains < & >.'); - print "\n

    \n"; - - /** - * building XML declaration - */ - print 'building XML declaration:
    '; - print htmlspecialchars(XML_Util::getXMLDeclaration()); - print "\n

    \n"; - - print 'building XML declaration with additional attributes:
    '; - print htmlspecialchars(XML_Util::getXMLDeclaration('1.0', 'UTF-8', true)); - print "\n

    \n"; - - /** - * building document type declaration - */ - print 'building DocType declaration:
    '; - print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', - 'http://pear.php.net/dtd/package-1.0')); - print "\n

    \n"; - - print 'building DocType declaration with public ID (does not exist):
    '; - print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', - array('uri' => 'http://pear.php.net/dtd/package-1.0', - 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1'))); - print "\n

    \n"; - - print 'building DocType declaration with internal DTD:
    '; - print '
    ';
    -    print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 
    -        'http://pear.php.net/dtd/package-1.0', 
    -        ''));
    -    print '
    '; - print "\n

    \n"; - - /** - * creating an attribute string - */ - $att = array( - 'foo' => 'bar', - 'argh' => 'tomato' - ); - - print 'converting array to string:
    '; - print XML_Util::attributesToString($att); - print "\n

    \n"; - - - /** - * creating an attribute string with linebreaks - */ - $att = array( - 'foo' => 'bar', - 'argh' => 'tomato' - ); - - print 'converting array to string (including line breaks):
    '; - print '
    ';
    -    print XML_Util::attributesToString($att, true, true);
    -    print '
    '; - print "\n

    \n"; - - - /** - * splitting a qualified tag name - */ - print 'splitting qualified tag name:
    '; - print '
    ';
    -    print_r(XML_Util::splitQualifiedName('xslt:stylesheet'));
    -    print '
    '; - print "\n
    \n"; - - - /** - * splitting a qualified tag name (no namespace) - */ - print 'splitting qualified tag name (no namespace):
    '; - print '
    ';
    -    print_r(XML_Util::splitQualifiedName('foo'));
    -    print '
    '; - print "\n
    \n"; - - /** - * splitting a qualified tag name (no namespace, but default namespace specified) - */ - print 'splitting qualified tag name ' - . '(no namespace, but default namespace specified):
    '; - print '
    ';
    -    print_r(XML_Util::splitQualifiedName('foo', 'bar'));
    -    print '
    '; - print "\n
    \n"; - - /** - * verifying XML names - */ - print 'verifying \'My private tag\':
    '; - print '
    ';
    -    print_r(XML_Util::isValidname('My Private Tag'));
    -    print '
    '; - print "\n

    \n"; - - print 'verifying \'-MyTag\':
    '; - print '
    ';
    -    print_r(XML_Util::isValidname('-MyTag'));
    -    print '
    '; - print "\n

    \n"; - - /** - * creating an XML tag - */ - $tag = array( - 'namespace' => 'foo', - 'localPart' => 'bar', - 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - 'content' => 'I\'m inside the tag' - ); - - print 'creating a tag with namespace and local part:
    '; - print htmlentities(XML_Util::createTagFromArray($tag)); - print "\n

    \n"; - - /** - * creating an XML tag - */ - $tag = array( - 'qname' => 'foo:bar', - 'namespaceUri' => 'http://foo.com', - 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - 'content' => 'I\'m inside the tag' - ); - - print 'creating a tag with qualified name and namespaceUri:
    '; - print htmlentities(XML_Util::createTagFromArray($tag)); - print "\n

    \n"; - - /** - * creating an XML tag - */ - $tag = array( - 'qname' => 'bar', - 'namespaceUri' => 'http://foo.com', - 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable') - ); - - print 'creating an empty tag without namespace but namespace Uri:
    '; - print htmlentities(XML_Util::createTagFromArray($tag)); - print "\n

    \n"; - - /** - * creating an XML tag with more namespaces - */ - $tag = array( - 'namespace' => 'foo', - 'localPart' => 'bar', - 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - 'content' => 'I\'m inside the tag', - 'namespaces' => array( - 'bar' => 'http://bar.com', - 'pear' => 'http://pear.php.net', - ) - ); - - print 'creating an XML tag with more namespaces:
    '; - print htmlentities(XML_Util::createTagFromArray($tag)); - print "\n

    \n"; - - /** - * creating an XML tag with a CData Section - */ - $tag = array( - 'qname' => 'foo', - 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - 'content' => 'I\'m inside the tag' - ); - - print 'creating a tag with CData section:
    '; - print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_CDATA_SECTION)); - print "\n

    \n"; - - /** - * creating an XML tag with a CData Section - */ - $tag = array( - 'qname' => 'foo', - 'attributes' => array('key' => 'value', 'argh' => 'tütü'), - 'content' => - 'Also XHTML-tags can be created ' - . 'and HTML entities can be replaced Ä ä Ü ö <>.' - ); - - print 'creating a tag with HTML entities:
    '; - print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_ENTITIES_HTML)); - print "\n

    \n"; - - /** - * creating an XML tag with createTag - */ - print 'creating a tag with createTag:
    '; - print htmlentities(XML_Util::createTag('myNs:myTag', - array('foo' => 'bar'), - 'This is inside the tag', - 'http://www.w3c.org/myNs#')); - print "\n

    \n"; - - - /** - * trying to create an XML tag with an array as content - */ - $tag = array( - 'qname' => 'bar', - 'content' => array('foo' => 'bar') - ); - print 'trying to create an XML tag with an array as content:
    '; - print '
    ';
    -    print_r(XML_Util::createTagFromArray($tag));
    -    print '
    '; - print "\n

    \n"; - - /** - * trying to create an XML tag without a name - */ - $tag = array( - 'attributes' => array('foo' => 'bar'), - ); - print 'trying to create an XML tag without a name:
    '; - print '
    ';
    -    print_r(XML_Util::createTagFromArray($tag));
    -    print '
    '; - print "\n

    \n"; -?> -XML_Util-1.2.1/examples/example2.php100644 1750 1750 11441 11117075466 12467 - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category XML - * @package XML_Util - * @subpackage Examples - * @author Stephan Schmidt - * @copyright 2003-2008 Stephan Schmidt - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: example2.php,v 1.11 2008/05/05 19:03:13 ashnazg Exp $ - * @link http://pear.php.net/package/XML_Util - */ - - /** - * set error level - */ - error_reporting(E_ALL); - - require_once 'XML/Util.php'; - - /** - * creating a start element - */ - print 'creating a start element:
    '; - print htmlentities(XML_Util::createStartElement('myNs:myTag', - array('foo' => 'bar'), 'http://www.w3c.org/myNs#')); - print "\n

    \n"; - - - /** - * creating a start element - */ - print 'creating a start element:
    '; - print htmlentities(XML_Util::createStartElement('myTag', - array(), 'http://www.w3c.org/myNs#')); - print "\n

    \n"; - - /** - * creating a start element - */ - print 'creating a start element:
    '; - print '
    ';
    -    print htmlentities(XML_Util::createStartElement('myTag', 
    -        array('foo' => 'bar', 'argh' => 'tomato'), 
    -        'http://www.w3c.org/myNs#', true));
    -    print '
    '; - print "\n

    \n"; - - - /** - * creating an end element - */ - print 'creating an end element:
    '; - print htmlentities(XML_Util::createEndElement('myNs:myTag')); - print "\n

    \n"; - - /** - * creating a CData section - */ - print 'creating a CData section:
    '; - print htmlentities(XML_Util::createCDataSection('I am content.')); - print "\n

    \n"; - - /** - * creating a comment - */ - print 'creating a comment:
    '; - print htmlentities(XML_Util::createComment('I am a comment.')); - print "\n

    \n"; - - /** - * creating an XML tag with multiline mode - */ - $tag = array( - 'qname' => 'foo:bar', - 'namespaceUri' => 'http://foo.com', - 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - 'content' => 'I\'m inside the tag & contain dangerous chars' - ); - - print 'creating a tag with qualified name and namespaceUri:
    '; - print '
    ';
    -    print htmlentities(XML_Util::createTagFromArray($tag, 
    -        XML_UTIL_REPLACE_ENTITIES, true));
    -    print '
    '; - print "\n

    \n"; - - /** - * create an attribute string without replacing the entities - */ - $atts = array('series' => 'Starsky & Hutch', 'channel' => 'ABC'); - print 'creating a attribute string, ' - . 'entities in values already had been replaced:
    '; - print htmlentities(XML_Util::attributesToString($atts, - true, false, false, false, XML_UTIL_ENTITIES_NONE)); - print "\n

    \n"; - - /** - * using the array-syntax for attributesToString() - */ - $atts = array('series' => 'Starsky & Hutch', 'channel' => 'ABC'); - print 'using the array-syntax for attributesToString()
    '; - print htmlentities(XML_Util::attributesToString($atts, - array('entities' => XML_UTIL_ENTITIES_NONE))); - print "\n

    \n"; - - -?> -XML_Util-1.2.1/tests/AllTests.php100644 1750 1750 7060 11117075466 12013 - * @license http://www.opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: AllTests.php,v 1.5 2008/05/30 11:53:09 ashnazg Exp $ - * @link http://pear.php.net/package/XML_Util - * @since 1.2.0a1 - */ - - -/** - * Check PHP version... PhpUnit v3+ requires at least PHP v5.1.4 - */ -if (version_compare(PHP_VERSION, "5.1.4") < 0) { - // Cannnot run test suites - echo 'Cannot run test suite via PhpUnit... requires at least PHP v5.1.4.' . PHP_EOL; - echo 'Use "pear run-tests -p xml_util" to run the PHPT tests directly.' . PHP_EOL -; - exit(1); -} - - -/** - * Derive the "main" method name - * @internal PhpUnit would have to rename PHPUnit_MAIN_METHOD to PHPUNIT_MAIN_METHOD - * to make this usage meet the PEAR CS... we cannot rename it here. - */ -if (!defined('PHPUnit_MAIN_METHOD')) { - define('PHPUnit_MAIN_METHOD', 'XML_Util_AllTests::main'); -} - - -/* - * Files needed by PhpUnit - */ -require_once 'PHPUnit/Framework.php'; -require_once 'PHPUnit/TextUI/TestRunner.php'; -require_once 'PHPUnit/Extensions/PhptTestSuite.php'; - -/* - * You must add each additional class-level test suite file here - */ -// there are no PhpUnit test files... only PHPTs.. so nothing is listed here - -/** - * directory where PHPT tests are located - */ -define('XML_UTIL_DIR_PHPT', dirname(__FILE__)); - -/** - * Master Unit Test Suite class for XML_Util - * - * This top-level test suite class organizes - * all class test suite files, - * so that the full suite can be run - * by PhpUnit or via "pear run-tests -up xml_util". - * - * @category XML - * @package XML_Util - * @subpackage UnitTesting - * @author Chuck Burgess - * @license http://www.opensource.org/licenses/bsd-license.php New BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/XML_Util - * @since 1.2.0a1 - */ -class XML_Util_AllTests -{ - - /** - * Launches the TextUI test runner - * - * @return void - * @uses PHPUnit_TextUI_TestRunner - */ - public static function main() - { - PHPUnit_TextUI_TestRunner::run(self::suite()); - } - - - /** - * Adds all class test suites into the master suite - * - * @return PHPUnit_Framework_TestSuite a master test suite - * containing all class test suites - * @uses PHPUnit_Framework_TestSuite - */ - public static function suite() - { - $suite = new PHPUnit_Framework_TestSuite( - 'XML_Util Full Suite of Unit Tests'); - - /* - * You must add each additional class-level test suite name here - */ - // there are no PhpUnit test files... only PHPTs.. so nothing is listed here - - /* - * add PHPT tests - */ - $phpt = new PHPUnit_Extensions_PhptTestSuite(XML_UTIL_DIR_PHPT); - $suite->addTestSuite($phpt); - - return $suite; - } -} - -/** - * Call the main method if this file is executed directly - * @internal PhpUnit would have to rename PHPUnit_MAIN_METHOD to PHPUNIT_MAIN_METHOD - * to make this usage meet the PEAR CS... we cannot rename it here. - */ -if (PHPUnit_MAIN_METHOD == 'XML_Util_AllTests::main') { - XML_Util_AllTests::main(); -} - -/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ -?> -XML_Util-1.2.1/tests/testBasic_apiVersion.phpt100644 1750 1750 701 11117075466 14537 --TEST-- -XML_Util::apiVersion() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - ---EXPECT-- -=====XML_Util::apiVersion() basic tests===== - -TEST: basic apiVersion() call -1.1 -XML_Util-1.2.1/tests/testBasic_attributesToString.phpt100644 1750 1750 7057 11117075466 16333 --TEST-- -XML_Util::attributesToString() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - "bar", "boo" => "baz"); -$sort1 = array( - 'multiline' => true, - 'indent' => '----', - 'linebreak' => "^", - 'entities' => XML_UTIL_ENTITIES_XML, - 'sort' => true -); -$sort2 = array( - 'multiline' => true, - 'indent' => '----', - 'linebreak' => "^", - 'entities' => XML_UTIL_ENTITIES_XML, -); - -echo "TEST: basic usage" . PHP_EOL; -echo XML_Util::attributesToString($att) . PHP_EOL . PHP_EOL; - -echo "TEST: explicit \$sort = true" . PHP_EOL; -echo XML_Util::attributesToString($att, true) . PHP_EOL . PHP_EOL; - -echo "TEST: explicit \$sort = false" . PHP_EOL; -echo XML_Util::attributesToString($att, false) . PHP_EOL . PHP_EOL; - -echo "TEST: explicit \$multiline = false" . PHP_EOL; -echo XML_Util::attributesToString($att, true, false) . PHP_EOL . PHP_EOL; - -echo "TEST: explicit \$multiline = true" . PHP_EOL; -echo XML_Util::attributesToString($att, true, true) . PHP_EOL . PHP_EOL; - -echo "TEST: explicit \$indent = ' ' (8 spaces)" . PHP_EOL; -echo XML_Util::attributesToString($att, true, true, ' ') . PHP_EOL . PHP_EOL; - -echo "TEST: explicit \$linebreak = '^' (some dummy char)" . PHP_EOL; -echo XML_Util::attributesToString($att, true, true, '^') . PHP_EOL . PHP_EOL; - -echo "TEST: passing \$sort array of options that includes 'sort'" . PHP_EOL; -echo XML_Util::attributesToString($att, $sort1) . PHP_EOL . PHP_EOL; - -echo "TEST: passing \$sort array of options that doesn't include 'sort'" . PHP_EOL; -echo XML_Util::attributesToString($att, $sort2) . PHP_EOL . PHP_EOL; - -echo "TEST: do not replace entities" . PHP_EOL; -$arr = array("foo" => "b@&r", "boo" => "b> "b@&r", "boo" => "b> "b@&r", "boo" => "b> "b@&r", "boo" => "b> ---EXPECT-- -=====XML_Util::attributesToString() basic tests===== - -TEST: basic usage - boo="baz" foo="bar" - -TEST: explicit $sort = true - boo="baz" foo="bar" - -TEST: explicit $sort = false - foo="bar" boo="baz" - -TEST: explicit $multiline = false - boo="baz" foo="bar" - -TEST: explicit $multiline = true - boo="baz" - foo="bar" - -TEST: explicit $indent = ' ' (8 spaces) - boo="baz" - foo="bar" - -TEST: explicit $linebreak = '^' (some dummy char) - boo="baz" -^foo="bar" - -TEST: passing $sort array of options that includes 'sort' - boo="baz" -----foo="bar" - -TEST: passing $sort array of options that doesn't include 'sort' - boo="baz" -----foo="bar" - -TEST: do not replace entities - boo="b> -# created for v1.2.0a1 2008-05-04 ---FILE-- -"; -$otherTag = "baz"; -$xhtmlTag = ""; - -echo "TEST: basic usage" . PHP_EOL; -echo XML_Util::collapseEmptyTags($emptyTag) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage alongside non-empty tag" . PHP_EOL; -echo XML_Util::collapseEmptyTags($emptyTag . $otherTag) . PHP_EOL . PHP_EOL; - -echo "TEST: one empty tag, with COLLAPSE_ALL set" . PHP_EOL; -echo XML_Util::collapseEmptyTags($emptyTag, XML_UTIL_COLLAPSE_ALL) . PHP_EOL . PHP_EOL; - -echo "TEST: one empty tag alongside non-empty tag, with COLLAPSE_ALL set" . PHP_EOL; -echo XML_Util::collapseEmptyTags($emptyTag . $otherTag, XML_UTIL_COLLAPSE_ALL) . PHP_EOL . PHP_EOL; - -echo "TEST: one empty tag, with COLLAPSE_XHTML_ONLY set" . PHP_EOL; -echo XML_Util::collapseEmptyTags($emptyTag, XML_UTIL_COLLAPSE_XHTML_ONLY) . PHP_EOL . PHP_EOL; - -echo "TEST: one empty tag alongside non-empty tag, with COLLAPSE_XHTML_ONLY set" . PHP_EOL; -echo XML_Util::collapseEmptyTags($emptyTag . $xhtmlTag . $otherTag, XML_UTIL_COLLAPSE_XHTML_ONLY) . PHP_EOL . PHP_EOL; -?> ---EXPECT-- -=====XML_Util::collapseEmptyTags() basic tests===== - -TEST: basic usage - - -TEST: basic usage alongside non-empty tag -baz - -TEST: one empty tag, with COLLAPSE_ALL set - - -TEST: one empty tag alongside non-empty tag, with COLLAPSE_ALL set -baz - -TEST: one empty tag, with COLLAPSE_XHTML_ONLY set - - -TEST: one empty tag alongside non-empty tag, with COLLAPSE_XHTML_ONLY set -baz -XML_Util-1.2.1/tests/testBasic_createCDataSection.phpt100644 1750 1750 756 11117075466 16117 --TEST-- -XML_Util::createCDataSection() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - ---EXPECT-- -=====XML_Util::createCDataSection() basic tests===== - -TEST: basic usage - -XML_Util-1.2.1/tests/testBasic_createComment.phpt100644 1750 1750 727 11117075466 15216 --TEST-- -XML_Util::createComment() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - ---EXPECT-- -=====XML_Util::createComment() basic tests===== - -TEST: basic usage - -XML_Util-1.2.1/tests/testBasic_createEndElement.phpt100644 1750 1750 1270 11117075466 15646 --TEST-- -XML_Util::createEndElement() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - ---EXPECT-- -=====XML_Util::createEndElement() basic tests===== - -TEST: basic usage (myTag) - - -TEST: basic usage with a namespaced tag (myNs:myTag) - -XML_Util-1.2.1/tests/testBasic_createStartElement.phpt100644 1750 1750 7275 11117075466 16250 --TEST-- -XML_Util::createStartElement() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - "bar") -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag only, passing '' as attribute arg" . PHP_EOL; -echo XML_Util::createStartElement( - 'myNs:myTag', - '' -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attributes and namespace" . PHP_EOL; -echo XML_Util::createStartElement( - "myNs:myTag", - array("foo" => "bar"), - "http://www.w3c.org/myNs#" -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with empty attributes, whose namespaceUri is not a full namespace" . PHP_EOL; -echo XML_Util::createStartElement( - 'myTag', - '', - 'foo' -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attributes, namespace, and multiline = true" . PHP_EOL; -echo XML_Util::createStartElement( - "myNs:myTag", - array("foo" => "bar"), - "http://www.w3c.org/myNs#", - true -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attributes, namespace, multiline = true, and indent = (2 spaces only)" . PHP_EOL; -echo XML_Util::createStartElement( - "myNs:myTag", - array("foo" => "bar"), - "http://www.w3c.org/myNs#", - true, - ' ' -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attributes, namespace, multiline = true, indent = (2 spaces only), and linebreak = '^'" . PHP_EOL; -echo XML_Util::createStartElement( - "myNs:myTag", - array("foo" => "bar"), - "http://www.w3c.org/myNs#", - true, - ' ', - '^' -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attributes, namespace, multiline = true, indent = (2 spaces only), linebreak = '^', and sortAttributes = true" . PHP_EOL; -echo XML_Util::createStartElement( - "myNs:myTag", - array("foo" => "bar", "boo" => "baz"), - "http://www.w3c.org/myNs#", - true, - ' ', - '^', - true -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attributes, namespace, multiline = true, indent = (2 spaces only), linebreak = '^', and sortAttributes = false" . PHP_EOL; -echo XML_Util::createStartElement( - "myNs:myTag", - array("foo" => "bar", "boo" => "baz"), - "http://www.w3c.org/myNs#", - true, - ' ', - '^', - false -) . PHP_EOL . PHP_EOL; -?> ---EXPECT-- -=====XML_Util::createStartElement() basic tests===== - -TEST: tag only - - -TEST: tag with attributes - - -TEST: tag only, passing '' as attribute arg - - -TEST: tag with attributes and namespace - - -TEST: tag with empty attributes, whose namespaceUri is not a full namespace - - -TEST: tag with attributes, namespace, and multiline = true - - -TEST: tag with attributes, namespace, multiline = true, and indent = (2 spaces only) - - -TEST: tag with attributes, namespace, multiline = true, indent = (2 spaces only), and linebreak = '^' - - -TEST: tag with attributes, namespace, multiline = true, indent = (2 spaces only), linebreak = '^', and sortAttributes = true - - -TEST: tag with attributes, namespace, multiline = true, indent = (2 spaces only), linebreak = '^', and sortAttributes = false - -XML_Util-1.2.1/tests/testBasic_createTag.phpt100644 1750 1750 13434 11117075466 14366 --TEST-- -XML_Util::createTag() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - "bar") -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute and content" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag" -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, and namespace" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag", - "http://www.w3c.org/myNs#" -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, and REPLACE_ENTITIES" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, and CDATA_SECTION" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_CDATA_SECTION -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, and multiline = false" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES, - false -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, and multiline = true" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES, - true -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, and indent = (2 spaces)" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES, - true, - ' ' -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, indent = (2 spaces), and linebreak = '^'" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES, - true, - ' ', - '^' -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = true" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar", "boo" => "baz"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES, - true, - ' ', - '^', - true -) . PHP_EOL . PHP_EOL; - -echo "TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = false" . PHP_EOL; -echo XML_Util::createTag( - "myNs:myTag", - array("foo" => "bar", "boo" => "baz"), - "This is inside the tag and has < & @ > in it", - "http://www.w3c.org/myNs#", - XML_UTIL_REPLACE_ENTITIES, - true, - ' ', - '^', - false -) . PHP_EOL . PHP_EOL; -?> ---EXPECT-- -=====XML_Util::createTag() basic tests===== - -TEST: tag with attribute - - -TEST: tag with attribute and content -This is inside the tag - -TEST: tag with attribute, content, and namespace -This is inside the tag - -TEST: tag with attribute, content, namespace, and REPLACE_ENTITIES -This is inside the tag and has < & @ > in it - -TEST: tag with attribute, content, namespace, and CDATA_SECTION - in it]]> - -TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, and multiline = false -This is inside the tag and has < & @ > in it - -TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, and multiline = true -This is inside the tag and has < & @ > in it - -TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, and indent = (2 spaces) -This is inside the tag and has < & @ > in it - -TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, indent = (2 spaces), and linebreak = '^' -This is inside the tag and has < & @ > in it - -TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = true -This is inside the tag and has < & @ > in it - -TEST: tag with attribute, content, namespace, REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = false -This is inside the tag and has < & @ > in it -XML_Util-1.2.1/tests/testBasic_createTagFromArray.phpt100644 1750 1750 22131 11117075466 16203 --TEST-- -XML_Util::createTagFromArray() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - "bar", -); -$tag1 = array( - "qname" => "foo:bar", -); -$tag2 = array( - "qname" => "foo:bar", - "namespaceUri" => "http://foo.com", -); -$tag3 = array( - "qname" => "foo:bar", - "namespaceUri" => "http://foo.com", - "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), -); -$tag4 = array( - "qname" => "foo:bar", - "namespaceUri" => "http://foo.com", - "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), - "content" => "I'm inside the tag", -); -$tag5 = array( - "qname" => "foo:bar", - "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), - "content" => "I'm inside the tag", -); -$tag6 = array( - "qname" => "foo:bar", - "namespaceUri" => "http://foo.com", - "content" => "I'm inside the tag", -); -$tag7 = array( - "namespaceUri" => "http://foo.com", - "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ), - "content" => "I'm inside the tag", -); - -$tag8 = array( - 'content' => array('foo', 'bar') -); - -$tag9 = array( - 'qname' => 'foo:bar', - 'namespaces' => array('ns1' => 'uri1', 'ns2' => 'uri2') -); - -$tag10 = array( - 'namespace' => 'http://foo.org', - 'localPart' => 'bar' -); - -$tag11 = array( - 'namespace' => '', - 'localPart' => 'bar' -); - -$tag12 = array( - 'localPart' => 'foo', - 'namespaceUri' => 'http://bar.org' -); - -echo "TEST: basic usage with an invalid array" . PHP_EOL; -echo XML_Util::createTagFromArray($bad) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname only)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag1) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname and namespaceUri)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag2) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, and attributes)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag3) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, attributes, and content)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag5) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, and content)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag6) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (namespaceUri, attributes, and content)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag7) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), plus REPLACE_ENTITIES" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), plus ENTITIES_NONE" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_ENTITIES_NONE) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, and multiline = false" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES, false) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, and multiline = true" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES, true) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, and indent = (2 spaces)" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES, true, ' ') . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, indent = (2 spaces), and linebreak = '^'" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES, true, ' ', '^') . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = true" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES, true, ' ', '^', true) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = false" . PHP_EOL; -echo XML_Util::createTagFromArray($tag4, XML_UTIL_REPLACE_ENTITIES, true, ' ', '^', false) . PHP_EOL . PHP_EOL; - -echo 'TEST: cause a non-scalar error on the content tag' . PHP_EOL; -echo XML_Util::createTagFromArray($tag8) . PHP_EOL . PHP_EOL; - -echo 'TEST: handle an array of namespaces being passed' . PHP_EOL; -echo XML_Util::createTagFromArray($tag9) . PHP_EOL . PHP_EOL; - -echo 'TEST: qname is derived from namespace + localPart' . PHP_EOL; -echo XML_Util::createTagFromArray($tag10) . PHP_EOL . PHP_EOL; - -echo 'TEST: qname is derived from localPart only' . PHP_EOL; -echo XML_Util::createTagFromArray($tag11) . PHP_EOL . PHP_EOL; - -echo 'TEST: namespaceUri is given, but namespace is not' . PHP_EOL; -echo XML_Util::createTagFromArray($tag12) . PHP_EOL . PHP_EOL; -?> ---EXPECT-- -=====XML_Util::createTagFromArray() basic tests===== - -TEST: basic usage with an invalid array -You must either supply a qualified name (qname) or local tag name (localPart). - -TEST: basic usage with a valid array (qname only) - - -TEST: basic usage with a valid array (qname and namespaceUri) - - -TEST: basic usage with a valid array (qname, namespaceUri, and attributes) - - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content) -I'm inside the tag - -TEST: basic usage with a valid array (qname, attributes, and content) -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, and content) -I'm inside the tag - -TEST: basic usage with a valid array (namespaceUri, attributes, and content) -You must either supply a qualified name (qname) or local tag name (localPart). - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), plus REPLACE_ENTITIES -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), plus ENTITIES_NONE -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, and multiline = false -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, and multiline = true -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, and indent = (2 spaces) -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, indent = (2 spaces), and linebreak = '^' -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = true -I'm inside the tag - -TEST: basic usage with a valid array (qname, namespaceUri, attributes, and content), REPLACE_ENTITIES, multiline = true, indent = (2 spaces), linebreak = '^', and sortAttributes = false -I'm inside the tag - -TEST: cause a non-scalar error on the content tag -Supplied non-scalar value as tag content - -TEST: handle an array of namespaces being passed - - -TEST: qname is derived from namespace + localPart - - -TEST: qname is derived from localPart only - - -TEST: namespaceUri is given, but namespace is not - -XML_Util-1.2.1/tests/testBasic_getDocTypeDeclaration.phpt100644 1750 1750 2754 11117075466 16667 --TEST-- -XML_Util::getDocTypeDeclaration() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - 'http://pear.php.net/dtd/package-1.0', - 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1' -); -$dtdEntry = ''; - -echo "TEST: using root and an array URI" . PHP_EOL; -echo XML_Util::getDocTypeDeclaration("rootTag", $uri) . PHP_EOL . PHP_EOL; - -echo "TEST: using root and an array URI and an internal DTD entry" . PHP_EOL; -echo XML_Util::getDocTypeDeclaration("rootTag", $uri, $dtdEntry) . PHP_EOL . PHP_EOL; -?> ---EXPECT-- -=====XML_Util::getDocTypeDeclaration() basic tests===== - -TEST: using root only - - -TEST: using root and a string URI - - -TEST: using root and an array URI - - -TEST: using root and an array URI and an internal DTD entry - -]> -XML_Util-1.2.1/tests/testBasic_getXmlDeclaration.phpt100644 1750 1750 2217 11117075466 16052 --TEST-- -XML_Util::getXmlDeclaration() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - ---EXPECT-- -=====XML_Util::getXmlDeclaration() basic tests===== - -TEST: using version only - - -TEST: using version and encoding - - -TEST: using version, encoding, and standalone flag - - -TEST: using version and standalone flag - -XML_Util-1.2.1/tests/testBasic_isValidName.phpt100644 1750 1750 2602 11117075466 14636 --TEST-- -XML_Util::isValidName() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- -getMessage() . PHP_EOL . PHP_EOL; -} else { - print "Valid XML name." . PHP_EOL . PHP_EOL; -} - -echo "TEST: invalid tag" . PHP_EOL; -$result = XML_Util::isValidName("invalidTag?"); -if (is_a($result, 'PEAR_Error')) { - print "Invalid XML name: " . $result->getMessage() . PHP_EOL . PHP_EOL; -} else { - print "Valid XML name." . PHP_EOL . PHP_EOL; -} - -echo "TEST: invalid tag that doesn't start with a letter" . PHP_EOL; -$result = XML_Util::isValidName("1234five"); -if (is_a($result, 'PEAR_Error')) { - print "Invalid XML name: " . $result->getMessage() . PHP_EOL . PHP_EOL; -} else { - print "Valid XML name." . PHP_EOL . PHP_EOL; -} - -?> ---EXPECT-- -=====XML_Util::isValidName() basic tests===== - -TEST: valid tag -Valid XML name. - -TEST: invalid tag -Invalid XML name: XML names may only contain alphanumeric chars, period, hyphen, colon and underscores - -TEST: invalid tag that doesn't start with a letter -Invalid XML name: XML names may only start with letter or underscore -XML_Util-1.2.1/tests/testBasic_raiseError.phpt100644 1750 1750 766 11117075466 14550 --TEST-- -XML_Util::raiseError() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- -getMessage() . PHP_EOL; -} -?> ---EXPECT-- -=====XML_Util::raiseError() basic tests===== - -PEAR Error: I am an error -XML_Util-1.2.1/tests/testBasic_replaceEntities.phpt100644 1750 1750 6260 11117075466 15566 --TEST-- -XML_Util::replaceEntities() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- -.'; -$utf8 = 'This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê'; - -echo "TEST: basic usage" . PHP_EOL; -echo XML_Util::replaceEntities($data) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage but with bogus \$replaceEntities arg" . PHP_EOL; -echo XML_Util::replaceEntities($data, 'I_AM_BOGUS') . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with ENTITIES_XML" . PHP_EOL; -echo XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_XML) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with ENTITIES_XML and UTF-8" . PHP_EOL; -echo XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_XML, 'UTF-8') . PHP_EOL . PHP_EOL; - -echo "TEST: utf8 usage with ENTITIES_XML and UTF-8" . PHP_EOL; -echo XML_Util::replaceEntities($utf8, XML_UTIL_ENTITIES_XML, 'UTF-8') . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with ENTITIES_XML_REQUIRED" . PHP_EOL; -echo XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_XML_REQUIRED) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with ENTITIES_XML_REQUIRED and UTF-8" . PHP_EOL; -echo XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_XML_REQUIRED, 'UTF-8') . PHP_EOL . PHP_EOL; - -echo "TEST: utf8 usage with ENTITIES_XML_REQUIRED and UTF-8" . PHP_EOL; -echo XML_Util::replaceEntities($utf8, XML_UTIL_ENTITIES_XML_REQUIRED, 'UTF-8') . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with ENTITIES_HTML" . PHP_EOL; -echo XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_HTML) . PHP_EOL . PHP_EOL; - -echo "TEST: basic usage with ENTITIES_HTML and UTF-8" . PHP_EOL; -echo XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_HTML, 'UTF-8') . PHP_EOL . PHP_EOL; - -echo "TEST: utf8 usage with ENTITIES_HTML and UTF-8" . PHP_EOL; -echo XML_Util::replaceEntities($utf8, XML_UTIL_ENTITIES_HTML, 'UTF-8') . PHP_EOL . PHP_EOL; -?> ---EXPECT-- -=====XML_Util::replaceEntities() basic tests===== - -TEST: basic usage -This string contains < & >. - -TEST: basic usage but with bogus $replaceEntities arg -This string contains < & >. - -TEST: basic usage with ENTITIES_XML -This string contains < & >. - -TEST: basic usage with ENTITIES_XML and UTF-8 -This string contains < & >. - -TEST: utf8 usage with ENTITIES_XML and UTF-8 -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê - -TEST: basic usage with ENTITIES_XML_REQUIRED -This string contains < & >. - -TEST: basic usage with ENTITIES_XML_REQUIRED and UTF-8 -This string contains < & >. - -TEST: utf8 usage with ENTITIES_XML_REQUIRED and UTF-8 -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê - -TEST: basic usage with ENTITIES_HTML -This string contains < & >. - -TEST: basic usage with ENTITIES_HTML and UTF-8 -This string contains < & >. - -TEST: utf8 usage with ENTITIES_HTML and UTF-8 -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê - -XML_Util-1.2.1/tests/testBasic_reverseEntities.phpt100644 1750 1750 6241 11117075466 15625 --TEST-- -XML_Util::reverseEntities() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - ---EXPECT-- -=====XML_Util::reverseEntities() basic tests===== - -TEST: basic usage -This string contains < & >. - -TEST: basic usage but with bogus $replaceEntities arg -This string contains < & >. - -TEST: basic usage with ENTITIES_XML -This string contains < & >. - -TEST: basic usage with ENTITIES_XML and UTF-8 -This string contains < & >. - -TEST: utf8 usage with ENTITIES_XML and UTF-8 -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê - -TEST: basic usage with ENTITIES_XML_REQUIRED -This string contains < & >. - -TEST: basic usage with ENTITIES_XML_REQUIRED and UTF-8 -This string contains < & >. - -TEST: utf8 usage with ENTITIES_XML_REQUIRED and UTF-8 -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê - -TEST: basic usage with ENTITIES_HTML -This string contains < & >. - -TEST: basic usage with ENTITIES_HTML and UTF-8 -This string contains < & >. - -TEST: utf8 usage with ENTITIES_HTML and UTF-8 -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê -XML_Util-1.2.1/tests/testBasic_splitQualifiedName.phpt100644 1750 1750 1727 11117075466 16231 --TEST-- -XML_Util::splitQualifiedName() basic tests ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - " . $return['namespace'] . PHP_EOL; -echo "localPart => " . $return['localPart'] . PHP_EOL; -echo PHP_EOL; - -echo "TEST: basic usage with namespace" . PHP_EOL; -$return = XML_Util::splitQualifiedName("stylesheet", "myNs"); -echo "namespace => " . $return['namespace'] . PHP_EOL; -echo "localPart => " . $return['localPart'] . PHP_EOL; -echo PHP_EOL; -?> ---EXPECT-- -=====XML_Util::splitQualifiedName() basic tests===== - -TEST: basic usage without namespace -namespace => xslt -localPart => stylesheet - -TEST: basic usage with namespace -namespace => myNs -localPart => stylesheet -XML_Util-1.2.1/tests/testBug_4950.phpt100644 1750 1750 1243 11117075466 12537 --TEST-- -XML_Util tests for Bug #4950 "Incorrect CDATA serializing" ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- - here!", - null, XML_UTIL_CDATA_SECTION) . PHP_EOL; - -?> ---EXPECT-- -=====XML_Util tests for Bug #4950 "Incorrect CDATA serializing"===== - -TEST: test case provided in bug report - here!]]> - -XML_Util-1.2.1/tests/testBug_5392.phpt100644 1750 1750 2111 11117075466 12533 --TEST-- -XML_Util tests for Bug #5392 "encoding of ISO-8859-1 is the only supported encoding" ---CREDITS-- -Chuck Burgess -# created for v1.2.0a1 2008-05-04 ---FILE-- -, & and " as well as ä, ö, ß, à and ê'; - -$replaced = XML_Util::replaceEntities($data, XML_UTIL_ENTITIES_HTML, 'UTF-8'); - -$reversed = XML_Util::reverseEntities($replaced, XML_UTIL_ENTITIES_HTML, 'UTF-8'); - -echo $replaced . PHP_EOL; -echo $reversed . PHP_EOL; - -?> ---EXPECT-- -=====XML_Util tests for Bug #5392 "encoding of ISO-8859-1 is the only supported encoding"===== - -TEST: test case provided in bug report -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê -This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê -XML_Util-1.2.1/Util.php100644 1750 1750 73350 11117075466 10060 - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category XML - * @package XML_Util - * @author Stephan Schmidt - * @copyright 2003-2008 Stephan Schmidt - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: Util.php,v 1.38 2008/11/13 00:03:38 ashnazg Exp $ - * @link http://pear.php.net/package/XML_Util - */ - -/** - * error code for invalid chars in XML name - */ -define('XML_UTIL_ERROR_INVALID_CHARS', 51); - -/** - * error code for invalid chars in XML name - */ -define('XML_UTIL_ERROR_INVALID_START', 52); - -/** - * error code for non-scalar tag content - */ -define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60); - -/** - * error code for missing tag name - */ -define('XML_UTIL_ERROR_NO_TAG_NAME', 61); - -/** - * replace XML entities - */ -define('XML_UTIL_REPLACE_ENTITIES', 1); - -/** - * embedd content in a CData Section - */ -define('XML_UTIL_CDATA_SECTION', 5); - -/** - * do not replace entitites - */ -define('XML_UTIL_ENTITIES_NONE', 0); - -/** - * replace all XML entitites - * This setting will replace <, >, ", ' and & - */ -define('XML_UTIL_ENTITIES_XML', 1); - -/** - * replace only required XML entitites - * This setting will replace <, " and & - */ -define('XML_UTIL_ENTITIES_XML_REQUIRED', 2); - -/** - * replace HTML entitites - * @link http://www.php.net/htmlentities - */ -define('XML_UTIL_ENTITIES_HTML', 3); - -/** - * Collapse all empty tags. - */ -define('XML_UTIL_COLLAPSE_ALL', 1); - -/** - * Collapse only empty XHTML tags that have no end tag. - */ -define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2); - -/** - * utility class for working with XML documents - * - - * @category XML - * @package XML_Util - * @author Stephan Schmidt - * @copyright 2003-2008 Stephan Schmidt - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version Release: 1.2.1 - * @link http://pear.php.net/package/XML_Util - */ -class XML_Util -{ - /** - * return API version - * - * @return string $version API version - * @access public - * @static - */ - function apiVersion() - { - return '1.1'; - } - - /** - * replace XML entities - * - * With the optional second parameter, you may select, which - * entities should be replaced. - * - * - * require_once 'XML/Util.php'; - * - * // replace XML entites: - * $string = XML_Util::replaceEntities('This string contains < & >.'); - * - * - * With the optional third parameter, you may pass the character encoding - * - * require_once 'XML/Util.php'; - * - * // replace XML entites in UTF-8: - * $string = XML_Util::replaceEntities( - * 'This string contains < & > as well as ä, ö, ß, à and ê', - * XML_UTIL_ENTITIES_HTML, - * 'UTF-8' - * ); - * - * - * @param string $string string where XML special chars - * should be replaced - * @param int $replaceEntities setting for entities in attribute values - * (one of XML_UTIL_ENTITIES_XML, - * XML_UTIL_ENTITIES_XML_REQUIRED, - * XML_UTIL_ENTITIES_HTML) - * @param string $encoding encoding value (if any)... - * must be a valid encoding as determined - * by the htmlentities() function - * - * @return string string with replaced chars - * @access public - * @static - * @see reverseEntities() - */ - function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML, - $encoding = 'ISO-8859-1') - { - switch ($replaceEntities) { - case XML_UTIL_ENTITIES_XML: - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - '\'' => ''' )); - break; - case XML_UTIL_ENTITIES_XML_REQUIRED: - return strtr($string, array( - '&' => '&', - '<' => '<', - '"' => '"' )); - break; - case XML_UTIL_ENTITIES_HTML: - return htmlentities($string, ENT_COMPAT, $encoding); - break; - } - return $string; - } - - /** - * reverse XML entities - * - * With the optional second parameter, you may select, which - * entities should be reversed. - * - * - * require_once 'XML/Util.php'; - * - * // reverse XML entites: - * $string = XML_Util::reverseEntities('This string contains < & >.'); - * - * - * With the optional third parameter, you may pass the character encoding - * - * require_once 'XML/Util.php'; - * - * // reverse XML entites in UTF-8: - * $string = XML_Util::reverseEntities( - * 'This string contains < & > as well as' - * . ' ä, ö, ß, à and ê', - * XML_UTIL_ENTITIES_HTML, - * 'UTF-8' - * ); - * - * - * @param string $string string where XML special chars - * should be replaced - * @param int $replaceEntities setting for entities in attribute values - * (one of XML_UTIL_ENTITIES_XML, - * XML_UTIL_ENTITIES_XML_REQUIRED, - * XML_UTIL_ENTITIES_HTML) - * @param string $encoding encoding value (if any)... - * must be a valid encoding as determined - * by the html_entity_decode() function - * - * @return string string with replaced chars - * @access public - * @static - * @see replaceEntities() - */ - function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML, - $encoding = 'ISO-8859-1') - { - switch ($replaceEntities) { - case XML_UTIL_ENTITIES_XML: - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - ''' => '\'' )); - break; - case XML_UTIL_ENTITIES_XML_REQUIRED: - return strtr($string, array( - '&' => '&', - '<' => '<', - '"' => '"' )); - break; - case XML_UTIL_ENTITIES_HTML: - return html_entity_decode($string, ENT_COMPAT, $encoding); - break; - } - return $string; - } - - /** - * build an xml declaration - * - * - * require_once 'XML/Util.php'; - * - * // get an XML declaration: - * $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true); - * - * - * @param string $version xml version - * @param string $encoding character encoding - * @param bool $standalone document is standalone (or not) - * - * @return string xml declaration - * @access public - * @static - * @uses attributesToString() to serialize the attributes of the XML declaration - */ - function getXMLDeclaration($version = '1.0', $encoding = null, - $standalone = null) - { - $attributes = array( - 'version' => $version, - ); - // add encoding - if ($encoding !== null) { - $attributes['encoding'] = $encoding; - } - // add standalone, if specified - if ($standalone !== null) { - $attributes['standalone'] = $standalone ? 'yes' : 'no'; - } - - return sprintf('', - XML_Util::attributesToString($attributes, false)); - } - - /** - * build a document type declaration - * - * - * require_once 'XML/Util.php'; - * - * // get a doctype declaration: - * $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd'); - * - * - * @param string $root name of the root tag - * @param string $uri uri of the doctype definition - * (or array with uri and public id) - * @param string $internalDtd internal dtd entries - * - * @return string doctype declaration - * @access public - * @static - * @since 0.2 - */ - function getDocTypeDeclaration($root, $uri = null, $internalDtd = null) - { - if (is_array($uri)) { - $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']); - } elseif (!empty($uri)) { - $ref = sprintf(' SYSTEM "%s"', $uri); - } else { - $ref = ''; - } - - if (empty($internalDtd)) { - return sprintf('', $root, $ref); - } else { - return sprintf("", $root, $ref, $internalDtd); - } - } - - /** - * create string representation of an attribute list - * - * - * require_once 'XML/Util.php'; - * - * // build an attribute string - * $att = array( - * 'foo' => 'bar', - * 'argh' => 'tomato' - * ); - * - * $attList = XML_Util::attributesToString($att); - * - * - * @param array $attributes attribute array - * @param bool|array $sort sort attribute list alphabetically, - * may also be an assoc array containing - * the keys 'sort', 'multiline', 'indent', - * 'linebreak' and 'entities' - * @param bool $multiline use linebreaks, if more than - * one attribute is given - * @param string $indent string used for indentation of - * multiline attributes - * @param string $linebreak string used for linebreaks of - * multiline attributes - * @param int $entities setting for entities in attribute values - * (one of XML_UTIL_ENTITIES_NONE, - * XML_UTIL_ENTITIES_XML, - * XML_UTIL_ENTITIES_XML_REQUIRED, - * XML_UTIL_ENTITIES_HTML) - * - * @return string string representation of the attributes - * @access public - * @static - * @uses replaceEntities() to replace XML entities in attribute values - * @todo allow sort also to be an options array - */ - function attributesToString($attributes, $sort = true, $multiline = false, - $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML) - { - /* - * second parameter may be an array - */ - if (is_array($sort)) { - if (isset($sort['multiline'])) { - $multiline = $sort['multiline']; - } - if (isset($sort['indent'])) { - $indent = $sort['indent']; - } - if (isset($sort['linebreak'])) { - $multiline = $sort['linebreak']; - } - if (isset($sort['entities'])) { - $entities = $sort['entities']; - } - if (isset($sort['sort'])) { - $sort = $sort['sort']; - } else { - $sort = true; - } - } - $string = ''; - if (is_array($attributes) && !empty($attributes)) { - if ($sort) { - ksort($attributes); - } - if ( !$multiline || count($attributes) == 1) { - foreach ($attributes as $key => $value) { - if ($entities != XML_UTIL_ENTITIES_NONE) { - if ($entities === XML_UTIL_CDATA_SECTION) { - $entities = XML_UTIL_ENTITIES_XML; - } - $value = XML_Util::replaceEntities($value, $entities); - } - $string .= ' ' . $key . '="' . $value . '"'; - } - } else { - $first = true; - foreach ($attributes as $key => $value) { - if ($entities != XML_UTIL_ENTITIES_NONE) { - $value = XML_Util::replaceEntities($value, $entities); - } - if ($first) { - $string .= ' ' . $key . '="' . $value . '"'; - $first = false; - } else { - $string .= $linebreak . $indent . $key . '="' . $value . '"'; - } - } - } - } - return $string; - } - - /** - * Collapses empty tags. - * - * @param string $xml XML - * @param int $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) - * or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones. - * - * @return string XML - * @access public - * @static - * @todo PEAR CS - unable to avoid "space after open parens" error - * in the IF branch - */ - function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) - { - if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) { - return preg_replace( - '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|' - . 'param)([^>]*)><\/\\1>/s', - '<\\1\\2 />', - $xml); - } else { - return preg_replace('/<(\w+)([^>]*)><\/\\1>/s', '<\\1\\2 />', $xml); - } - } - - /** - * create a tag - * - * This method will call XML_Util::createTagFromArray(), which - * is more flexible. - * - * - * require_once 'XML/Util.php'; - * - * // create an XML tag: - * $tag = XML_Util::createTag('myNs:myTag', - * array('foo' => 'bar'), - * 'This is inside the tag', - * 'http://www.w3c.org/myNs#'); - * - * - * @param string $qname qualified tagname (including namespace) - * @param array $attributes array containg attributes - * @param mixed $content the content - * @param string $namespaceUri URI of the namespace - * @param int $replaceEntities whether to replace XML special chars in - * content, embedd it in a CData section - * or none of both - * @param bool $multiline whether to create a multiline tag where - * each attribute gets written to a single line - * @param string $indent string used to indent attributes - * (_auto indents attributes so they start - * at the same column) - * @param string $linebreak string used for linebreaks - * @param bool $sortAttributes Whether to sort the attributes or not - * - * @return string XML tag - * @access public - * @static - * @see createTagFromArray() - * @uses createTagFromArray() to create the tag - */ - function createTag($qname, $attributes = array(), $content = null, - $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, - $multiline = false, $indent = '_auto', $linebreak = "\n", - $sortAttributes = true) - { - $tag = array( - 'qname' => $qname, - 'attributes' => $attributes - ); - - // add tag content - if ($content !== null) { - $tag['content'] = $content; - } - - // add namespace Uri - if ($namespaceUri !== null) { - $tag['namespaceUri'] = $namespaceUri; - } - - return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, - $indent, $linebreak, $sortAttributes); - } - - /** - * create a tag from an array - * this method awaits an array in the following format - *
    -     * array(
    -     *     // qualified name of the tag
    -     *     'qname' => $qname        
    -     *
    -     *     // namespace prefix (optional, if qname is specified or no namespace)
    -     *     'namespace' => $namespace    
    -     *
    -     *     // local part of the tagname (optional, if qname is specified)
    -     *     'localpart' => $localpart,   
    -     *
    -     *     // array containing all attributes (optional)
    -     *     'attributes' => array(),      
    -     *
    -     *     // tag content (optional)
    -     *     'content' => $content,     
    -     *
    -     *     // namespaceUri for the given namespace (optional)
    -     *     'namespaceUri' => $namespaceUri 
    -     * )
    -     * 
    - * - * - * require_once 'XML/Util.php'; - * - * $tag = array( - * 'qname' => 'foo:bar', - * 'namespaceUri' => 'http://foo.com', - * 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - * 'content' => 'I\'m inside the tag', - * ); - * // creating a tag with qualified name and namespaceUri - * $string = XML_Util::createTagFromArray($tag); - * - * - * @param array $tag tag definition - * @param int $replaceEntities whether to replace XML special chars in - * content, embedd it in a CData section - * or none of both - * @param bool $multiline whether to create a multiline tag where each - * attribute gets written to a single line - * @param string $indent string used to indent attributes - * (_auto indents attributes so they start - * at the same column) - * @param string $linebreak string used for linebreaks - * @param bool $sortAttributes Whether to sort the attributes or not - * - * @return string XML tag - * @access public - * @static - * @see createTag() - * @uses attributesToString() to serialize the attributes of the tag - * @uses splitQualifiedName() to get local part and namespace of a qualified name - * @uses createCDataSection() - * @uses raiseError() - */ - function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, - $multiline = false, $indent = '_auto', $linebreak = "\n", - $sortAttributes = true) - { - if (isset($tag['content']) && !is_scalar($tag['content'])) { - return XML_Util::raiseError('Supplied non-scalar value as tag content', - XML_UTIL_ERROR_NON_SCALAR_CONTENT); - } - - if (!isset($tag['qname']) && !isset($tag['localPart'])) { - return XML_Util::raiseError('You must either supply a qualified name ' - . '(qname) or local tag name (localPart).', - XML_UTIL_ERROR_NO_TAG_NAME); - } - - // if no attributes hav been set, use empty attributes - if (!isset($tag['attributes']) || !is_array($tag['attributes'])) { - $tag['attributes'] = array(); - } - - if (isset($tag['namespaces'])) { - foreach ($tag['namespaces'] as $ns => $uri) { - $tag['attributes']['xmlns:' . $ns] = $uri; - } - } - - if (!isset($tag['qname'])) { - // qualified name is not given - - // check for namespace - if (isset($tag['namespace']) && !empty($tag['namespace'])) { - $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart']; - } else { - $tag['qname'] = $tag['localPart']; - } - } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) { - // namespace URI is set, but no namespace - - $parts = XML_Util::splitQualifiedName($tag['qname']); - - $tag['localPart'] = $parts['localPart']; - if (isset($parts['namespace'])) { - $tag['namespace'] = $parts['namespace']; - } - } - - if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) { - // is a namespace given - if (isset($tag['namespace']) && !empty($tag['namespace'])) { - $tag['attributes']['xmlns:' . $tag['namespace']] = - $tag['namespaceUri']; - } else { - // define this Uri as the default namespace - $tag['attributes']['xmlns'] = $tag['namespaceUri']; - } - } - - // check for multiline attributes - if ($multiline === true) { - if ($indent === '_auto') { - $indent = str_repeat(' ', (strlen($tag['qname'])+2)); - } - } - - // create attribute list - $attList = XML_Util::attributesToString($tag['attributes'], - $sortAttributes, $multiline, $indent, $linebreak, $replaceEntities); - if (!isset($tag['content']) || (string)$tag['content'] == '') { - $tag = sprintf('<%s%s />', $tag['qname'], $attList); - } else { - switch ($replaceEntities) { - case XML_UTIL_ENTITIES_NONE: - break; - case XML_UTIL_CDATA_SECTION: - $tag['content'] = XML_Util::createCDataSection($tag['content']); - break; - default: - $tag['content'] = XML_Util::replaceEntities($tag['content'], - $replaceEntities); - break; - } - $tag = sprintf('<%s%s>%s', $tag['qname'], $attList, $tag['content'], - $tag['qname']); - } - return $tag; - } - - /** - * create a start element - * - * - * require_once 'XML/Util.php'; - * - * // create an XML start element: - * $tag = XML_Util::createStartElement('myNs:myTag', - * array('foo' => 'bar') ,'http://www.w3c.org/myNs#'); - * - * - * @param string $qname qualified tagname (including namespace) - * @param array $attributes array containg attributes - * @param string $namespaceUri URI of the namespace - * @param bool $multiline whether to create a multiline tag where each - * attribute gets written to a single line - * @param string $indent string used to indent attributes (_auto indents - * attributes so they start at the same column) - * @param string $linebreak string used for linebreaks - * @param bool $sortAttributes Whether to sort the attributes or not - * - * @return string XML start element - * @access public - * @static - * @see createEndElement(), createTag() - */ - function createStartElement($qname, $attributes = array(), $namespaceUri = null, - $multiline = false, $indent = '_auto', $linebreak = "\n", - $sortAttributes = true) - { - // if no attributes hav been set, use empty attributes - if (!isset($attributes) || !is_array($attributes)) { - $attributes = array(); - } - - if ($namespaceUri != null) { - $parts = XML_Util::splitQualifiedName($qname); - } - - // check for multiline attributes - if ($multiline === true) { - if ($indent === '_auto') { - $indent = str_repeat(' ', (strlen($qname)+2)); - } - } - - if ($namespaceUri != null) { - // is a namespace given - if (isset($parts['namespace']) && !empty($parts['namespace'])) { - $attributes['xmlns:' . $parts['namespace']] = $namespaceUri; - } else { - // define this Uri as the default namespace - $attributes['xmlns'] = $namespaceUri; - } - } - - // create attribute list - $attList = XML_Util::attributesToString($attributes, $sortAttributes, - $multiline, $indent, $linebreak); - $element = sprintf('<%s%s>', $qname, $attList); - return $element; - } - - /** - * create an end element - * - * - * require_once 'XML/Util.php'; - * - * // create an XML start element: - * $tag = XML_Util::createEndElement('myNs:myTag'); - * - * - * @param string $qname qualified tagname (including namespace) - * - * @return string XML end element - * @access public - * @static - * @see createStartElement(), createTag() - */ - function createEndElement($qname) - { - $element = sprintf('', $qname); - return $element; - } - - /** - * create an XML comment - * - * - * require_once 'XML/Util.php'; - * - * // create an XML start element: - * $tag = XML_Util::createComment('I am a comment'); - * - * - * @param string $content content of the comment - * - * @return string XML comment - * @access public - * @static - */ - function createComment($content) - { - $comment = sprintf('', $content); - return $comment; - } - - /** - * create a CData section - * - * - * require_once 'XML/Util.php'; - * - * // create a CData section - * $tag = XML_Util::createCDataSection('I am content.'); - * - * - * @param string $data data of the CData section - * - * @return string CData section with content - * @access public - * @static - */ - function createCDataSection($data) - { - return sprintf('', - preg_replace('/\]\]>/', ']]]]>', strval($data))); - - } - - /** - * split qualified name and return namespace and local part - * - * - * require_once 'XML/Util.php'; - * - * // split qualified tag - * $parts = XML_Util::splitQualifiedName('xslt:stylesheet'); - * - * the returned array will contain two elements: - *
    -     * array(
    -     *     'namespace' => 'xslt',
    -     *     'localPart' => 'stylesheet'
    -     * );
    -     * 
    - * - * @param string $qname qualified tag name - * @param string $defaultNs default namespace (optional) - * - * @return array array containing namespace and local part - * @access public - * @static - */ - function splitQualifiedName($qname, $defaultNs = null) - { - if (strstr($qname, ':')) { - $tmp = explode(':', $qname); - return array( - 'namespace' => $tmp[0], - 'localPart' => $tmp[1] - ); - } - return array( - 'namespace' => $defaultNs, - 'localPart' => $qname - ); - } - - /** - * check, whether string is valid XML name - * - *

    XML names are used for tagname, attribute names and various - * other, lesser known entities.

    - *

    An XML name may only consist of alphanumeric characters, - * dashes, undescores and periods, and has to start with a letter - * or an underscore.

    - * - * - * require_once 'XML/Util.php'; - * - * // verify tag name - * $result = XML_Util::isValidName('invalidTag?'); - * if (is_a($result, 'PEAR_Error')) { - * print 'Invalid XML name: ' . $result->getMessage(); - * } - * - * - * @param string $string string that should be checked - * - * @return mixed true, if string is a valid XML name, PEAR error otherwise - * @access public - * @static - * @todo support for other charsets - * @todo PEAR CS - unable to avoid 85-char limit on second preg_match - */ - function isValidName($string) - { - // check for invalid chars - if (!preg_match('/^[[:alpha:]_]$/', $string{0})) { - return XML_Util::raiseError('XML names may only start with letter ' - . 'or underscore', XML_UTIL_ERROR_INVALID_START); - } - - // check for invalid chars - if (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?$/', - $string) - ) { - return XML_Util::raiseError('XML names may only contain alphanumeric ' - . 'chars, period, hyphen, colon and underscores', - XML_UTIL_ERROR_INVALID_CHARS); - } - // XML name is valid - return true; - } - - /** - * replacement for XML_Util::raiseError - * - * Avoids the necessity to always require - * PEAR.php - * - * @param string $msg error message - * @param int $code error code - * - * @return PEAR_Error - * @access public - * @static - * @todo PEAR CS - should this use include_once instead? - */ - function raiseError($msg, $code) - { - require_once 'PEAR.php'; - return PEAR::raiseError($msg, $code); - } -} -?> -package.sig100644 1750 1750 305 11117075544 6362 -----BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.9 (GNU/Linux) - -iEYEABECAAYFAkk8e2QACgkQcqMhusJF8XULZgCg0iwVLWueraJzK5s1AesDkVzv -GucAn22sSv3QiTSUWG9BmakiW9hFsb4V -=g2mr ------END PGP SIGNATURE----- - - * @author Tomas V.V. Cox - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Installer.php 287446 2009-08-18 11:45:05Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Used for installation groups in package.xml 2.0 and platform exceptions - */ -require_once 'phar://go-pear.phar/' . 'OS/Guess.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php'; - -define('PEAR_INSTALLER_NOBINARY', -240); -/** - * Administration class used to install PEAR packages and maintain the - * installed package database. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Installer extends PEAR_Downloader -{ - // {{{ properties - - /** name of the package directory, for example Foo-1.0 - * @var string - */ - var $pkgdir; - - /** directory where PHP code files go - * @var string - */ - var $phpdir; - - /** directory where PHP extension files go - * @var string - */ - var $extdir; - - /** directory where documentation goes - * @var string - */ - var $docdir; - - /** installation root directory (ala PHP's INSTALL_ROOT or - * automake's DESTDIR - * @var string - */ - var $installroot = ''; - - /** debug level - * @var int - */ - var $debug = 1; - - /** temporary directory - * @var string - */ - var $tmpdir; - - /** - * PEAR_Registry object used by the installer - * @var PEAR_Registry - */ - var $registry; - - /** - * array of PEAR_Downloader_Packages - * @var array - */ - var $_downloadedPackages; - - /** List of file transactions queued for an install/upgrade/uninstall. - * - * Format: - * array( - * 0 => array("rename => array("from-file", "to-file")), - * 1 => array("delete" => array("file-to-delete")), - * ... - * ) - * - * @var array - */ - var $file_operations = array(); - - // }}} - - // {{{ constructor - - /** - * PEAR_Installer constructor. - * - * @param object $ui user interface object (instance of PEAR_Frontend_*) - * - * @access public - */ - function PEAR_Installer(&$ui) - { - parent::PEAR_Common(); - $this->setFrontendObject($ui); - $this->debug = $this->config->get('verbose'); - } - - function setOptions($options) - { - $this->_options = $options; - } - - function setConfig(&$config) - { - $this->config = &$config; - $this->_registry = &$config->getRegistry(); - } - - // }}} - - function _removeBackups($files) - { - foreach ($files as $path) { - $this->addFileOperation('removebackup', array($path)); - } - } - - // {{{ _deletePackageFiles() - - /** - * Delete a package's installed files, does not remove empty directories. - * - * @param string package name - * @param string channel name - * @param bool if true, then files are backed up first - * @return bool TRUE on success, or a PEAR error on failure - * @access protected - */ - function _deletePackageFiles($package, $channel = false, $backup = false) - { - if (!$channel) { - $channel = 'pear.php.net'; - } - - if (!strlen($package)) { - return $this->raiseError("No package to uninstall given"); - } - - if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { - // to avoid race conditions, include all possible needed files - require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/Task/Replace.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/Task/Unixeol.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/Task/Windowseol.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v1.php'; - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v2.php'; - } - - $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); - if ($filelist == null) { - return $this->raiseError("$channel/$package not installed"); - } - - $ret = array(); - foreach ($filelist as $file => $props) { - if (empty($props['installed_as'])) { - continue; - } - - $path = $props['installed_as']; - if ($backup) { - $this->addFileOperation('backup', array($path)); - $ret[] = $path; - } - - $this->addFileOperation('delete', array($path)); - } - - if ($backup) { - return $ret; - } - - return true; - } - - // }}} - // {{{ _installFile() - - /** - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private - */ - function _installFile($file, $atts, $tmp_path, $options) - { - // {{{ return if this file is meant for another platform - static $os; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } - - if (isset($atts['platform'])) { - if (empty($os)) { - $os = new OS_Guess(); - } - - if (strlen($atts['platform']) && $atts['platform']{0} == '!') { - $negate = true; - $platform = substr($atts['platform'], 1); - } else { - $negate = false; - $platform = $atts['platform']; - } - - if ((bool) $os->matchSignature($platform) === $negate) { - $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); - return PEAR_INSTALLER_SKIPPED; - } - } - // }}} - - $channel = $this->pkginfo->getChannel(); - // {{{ assemble the destination paths - switch ($atts['role']) { - case 'src': - case 'extsrc': - $this->source_files++; - return; - case 'doc': - case 'data': - case 'test': - $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . - DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); - unset($atts['baseinstalldir']); - break; - case 'ext': - case 'php': - $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); - break; - case 'script': - $dest_dir = $this->config->get('bin_dir', null, $channel); - break; - default: - return $this->raiseError("Invalid role `$atts[role]' for file $file"); - } - - $save_destdir = $dest_dir; - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - - if (dirname($file) != '.' && empty($atts['install-as'])) { - $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); - } - - if (empty($atts['install-as'])) { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); - } else { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; - } - $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; - - // Clean up the DIRECTORY_SEPARATOR mess - $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; - list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), - array(DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR), - array($dest_file, $orig_file)); - $final_dest_file = $installed_as = $dest_file; - if (isset($this->_options['packagingroot'])) { - $installedas_dest_dir = dirname($final_dest_file); - $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']); - } else { - $installedas_dest_dir = dirname($final_dest_file); - $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - } - - $dest_dir = dirname($final_dest_file); - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { - return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); - } - // }}} - - if (empty($this->_options['register-only']) && - (!file_exists($dest_dir) || !is_dir($dest_dir))) { - if (!$this->mkDirHier($dest_dir)) { - return $this->raiseError("failed to mkdir $dest_dir", - PEAR_INSTALLER_FAILED); - } - $this->log(3, "+ mkdir $dest_dir"); - } - - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (empty($atts['replacements'])) { - if (!file_exists($orig_file)) { - return $this->raiseError("file $orig_file does not exist", - PEAR_INSTALLER_FAILED); - } - - if (!@copy($orig_file, $dest_file)) { - return $this->raiseError("failed to write $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ cp $orig_file $dest_file"); - if (isset($atts['md5sum'])) { - $md5sum = md5_file($dest_file); - } - } else { - // {{{ file with replacements - if (!file_exists($orig_file)) { - return $this->raiseError("file does not exist", - PEAR_INSTALLER_FAILED); - } - - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } - - if (isset($atts['md5sum'])) { - $md5sum = md5($contents); - } - - $subst_from = $subst_to = array(); - foreach ($atts['replacements'] as $a) { - $to = ''; - if ($a['type'] == 'php-const') { - if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { - eval("\$to = $a[to];"); - } else { - if (!isset($options['soft'])) { - $this->log(0, "invalid php-const replacement: $a[to]"); - } - continue; - } - } elseif ($a['type'] == 'pear-config') { - if ($a['to'] == 'master_server') { - $chan = $this->_registry->getChannel($channel); - if (!PEAR::isError($chan)) { - $to = $chan->getServer(); - } else { - $to = $this->config->get($a['to'], null, $channel); - } - } else { - $to = $this->config->get($a['to'], null, $channel); - } - if (is_null($to)) { - if (!isset($options['soft'])) { - $this->log(0, "invalid pear-config replacement: $a[to]"); - } - continue; - } - } elseif ($a['type'] == 'package-info') { - if ($t = $this->pkginfo->packageInfo($a['to'])) { - $to = $t; - } else { - if (!isset($options['soft'])) { - $this->log(0, "invalid package-info replacement: $a[to]"); - } - continue; - } - } - if (!is_null($to)) { - $subst_from[] = $a['from']; - $subst_to[] = $to; - } - } - - $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); - if (sizeof($subst_from)) { - $contents = str_replace($subst_from, $subst_to, $contents); - } - - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - if (@fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - fclose($wp); - // }}} - } - - // {{{ check the md5 - if (isset($md5sum)) { - if (strtolower($md5sum) === strtolower($atts['md5sum'])) { - $this->log(2, "md5sum ok: $final_dest_file"); - } else { - if (empty($options['force'])) { - // delete the file - if (file_exists($dest_file)) { - unlink($dest_file); - } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError("bad md5sum for file $final_dest_file", - PEAR_INSTALLER_FAILED); - } - - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } else { - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } - } - } - // }}} - // {{{ set file permissions - if (!OS_WINDOWS) { - if ($atts['role'] == 'script') { - $mode = 0777 & ~(int)octdec($this->config->get('umask')); - $this->log(3, "+ chmod +x $dest_file"); - } else { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - } - - if ($atts['role'] != 'src') { - $this->addFileOperation("chmod", array($mode, $dest_file)); - if (!@chmod($dest_file, $mode)) { - if (!isset($options['soft'])) { - $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); - } - } - } - } - // }}} - - if ($atts['role'] == 'src') { - rename($dest_file, $final_dest_file); - $this->log(2, "renamed source file $dest_file to $final_dest_file"); - } else { - $this->addFileOperation("rename", array($dest_file, $final_dest_file, - $atts['role'] == 'ext')); - } - } - - // Store the full path where the file was installed for easy unistall - if ($atts['role'] != 'script') { - $loc = $this->config->get($atts['role'] . '_dir'); - } else { - $loc = $this->config->get('bin_dir'); - } - - if ($atts['role'] != 'src') { - $this->addFileOperation("installed_as", array($file, $installed_as, - $loc, - dirname(substr($installedas_dest_file, strlen($loc))))); - } - - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; - } - - // }}} - // {{{ _installFile2() - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private - */ - function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) - { - $atts = $real_atts; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } - - $channel = $pkg->getChannel(); - // {{{ assemble the destination paths - if (!in_array($atts['attribs']['role'], - PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { - return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . - "' for file $file"); - } - - $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); - $err = $role->setup($this, $pkg, $atts['attribs'], $file); - if (PEAR::isError($err)) { - return $err; - } - - if (!$role->isInstallable()) { - return; - } - - $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); - if (PEAR::isError($info)) { - return $info; - } - - list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; - if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { - return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); - } - - $final_dest_file = $installed_as = $dest_file; - if (isset($this->_options['packagingroot'])) { - $final_dest_file = $this->_prependPath($final_dest_file, - $this->_options['packagingroot']); - } - - $dest_dir = dirname($final_dest_file); - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - // }}} - - if (empty($this->_options['register-only'])) { - if (!file_exists($dest_dir) || !is_dir($dest_dir)) { - if (!$this->mkDirHier($dest_dir)) { - return $this->raiseError("failed to mkdir $dest_dir", - PEAR_INSTALLER_FAILED); - } - $this->log(3, "+ mkdir $dest_dir"); - } - } - - $attribs = $atts['attribs']; - unset($atts['attribs']); - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (!count($atts)) { // no tasks - if (!file_exists($orig_file)) { - return $this->raiseError("file $orig_file does not exist", - PEAR_INSTALLER_FAILED); - } - - if (!@copy($orig_file, $dest_file)) { - return $this->raiseError("failed to write $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ cp $orig_file $dest_file"); - if (isset($attribs['md5sum'])) { - $md5sum = md5_file($dest_file); - } - } else { // file with tasks - if (!file_exists($orig_file)) { - return $this->raiseError("file $orig_file does not exist", - PEAR_INSTALLER_FAILED); - } - - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } - - if (isset($attribs['md5sum'])) { - $md5sum = md5($contents); - } - - foreach ($atts as $tag => $raw) { - $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag); - $task = "PEAR_Task_$tag"; - $task = &new $task($this->config, $this, PEAR_TASK_INSTALL); - if (!$task->isScript()) { // scripts are only handled after installation - $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); - $res = $task->startSession($pkg, $contents, $final_dest_file); - if ($res === false) { - continue; // skip this file - } - - if (PEAR::isError($res)) { - return $res; - } - - $contents = $res; // save changes - } - - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - if (fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } - - fclose($wp); - } - } - - // {{{ check the md5 - if (isset($md5sum)) { - // Make sure the original md5 sum matches with expected - if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { - $this->log(2, "md5sum ok: $final_dest_file"); - - if (isset($contents)) { - // set md5 sum based on $content in case any tasks were run. - $real_atts['attribs']['md5sum'] = md5($contents); - } - } else { - if (empty($options['force'])) { - // delete the file - if (file_exists($dest_file)) { - unlink($dest_file); - } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError("bad md5sum for file $final_dest_file", - PEAR_INSTALLER_FAILED); - } - - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } else { - if (!isset($options['soft'])) { - $this->log(0, "warning : bad md5sum for file $final_dest_file"); - } - } - } - } else { - $real_atts['attribs']['md5sum'] = md5_file($dest_file); - } - - // }}} - // {{{ set file permissions - if (!OS_WINDOWS) { - if ($role->isExecutable()) { - $mode = 0777 & ~(int)octdec($this->config->get('umask')); - $this->log(3, "+ chmod +x $dest_file"); - } else { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - } - - if ($attribs['role'] != 'src') { - $this->addFileOperation("chmod", array($mode, $dest_file)); - if (!@chmod($dest_file, $mode)) { - if (!isset($options['soft'])) { - $this->log(0, "failed to change mode of $dest_file: $php_errormsg"); - } - } - } - } - // }}} - - if ($attribs['role'] == 'src') { - rename($dest_file, $final_dest_file); - $this->log(2, "renamed source file $dest_file to $final_dest_file"); - } else { - $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); - } - } - - // Store the full path where the file was installed for easy uninstall - if ($attribs['role'] != 'src') { - $loc = $this->config->get($role->getLocationConfig(), null, $channel); - $this->addFileOperation('installed_as', array($file, $installed_as, - $loc, - dirname(substr($installed_as, strlen($loc))))); - } - - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; - } - - // }}} - // {{{ addFileOperation() - - /** - * Add a file operation to the current file transaction. - * - * @see startFileTransaction() - * @param string $type This can be one of: - * - rename: rename a file ($data has 3 values) - * - backup: backup an existing file ($data has 1 value) - * - removebackup: clean up backups created during install ($data has 1 value) - * - chmod: change permissions on a file ($data has 2 values) - * - delete: delete a file ($data has 1 value) - * - rmdir: delete a directory if empty ($data has 1 value) - * - installed_as: mark a file as installed ($data has 4 values). - * @param array $data For all file operations, this array must contain the - * full path to the file or directory that is being operated on. For - * the rename command, the first parameter must be the file to rename, - * the second its new name, the third whether this is a PHP extension. - * - * The installed_as operation contains 4 elements in this order: - * 1. Filename as listed in the filelist element from package.xml - * 2. Full path to the installed file - * 3. Full path from the php_dir configuration variable used in this - * installation - * 4. Relative path from the php_dir that this file is installed in - */ - function addFileOperation($type, $data) - { - if (!is_array($data)) { - return $this->raiseError('Internal Error: $data in addFileOperation' - . ' must be an array, was ' . gettype($data)); - } - - if ($type == 'chmod') { - $octmode = decoct($data[0]); - $this->log(3, "adding to transaction: $type $octmode $data[1]"); - } else { - $this->log(3, "adding to transaction: $type " . implode(" ", $data)); - } - $this->file_operations[] = array($type, $data); - } - - // }}} - // {{{ startFileTransaction() - - function startFileTransaction($rollback_in_case = false) - { - if (count($this->file_operations) && $rollback_in_case) { - $this->rollbackFileTransaction(); - } - $this->file_operations = array(); - } - - // }}} - // {{{ commitFileTransaction() - - function commitFileTransaction() - { - $n = count($this->file_operations); - $this->log(2, "about to commit $n file operations"); - // {{{ first, check permissions and such manually - $errors = array(); - foreach ($this->file_operations as $tr) { - list($type, $data) = $tr; - switch ($type) { - case 'rename': - if (!file_exists($data[0])) { - $errors[] = "cannot rename file $data[0], doesn't exist"; - } - - // check that dest dir. is writable - if (!is_writable(dirname($data[1]))) { - $errors[] = "permission denied ($type): $data[1]"; - } - break; - case 'chmod': - // check that file is writable - if (!is_writable($data[1])) { - $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); - } - break; - case 'delete': - if (!file_exists($data[0])) { - $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); - } - // check that directory is writable - if (file_exists($data[0])) { - if (!is_writable(dirname($data[0]))) { - $errors[] = "permission denied ($type): $data[0]"; - } else { - // make sure the file to be deleted can be opened for writing - $fp = false; - if (!is_dir($data[0]) && - (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { - $errors[] = "permission denied ($type): $data[0]"; - } elseif ($fp) { - fclose($fp); - } - } - } - break; - } - - } - // }}} - $m = count($errors); - if ($m > 0) { - foreach ($errors as $error) { - if (!isset($this->_options['soft'])) { - $this->log(1, $error); - } - } - - if (!isset($this->_options['ignore-errors'])) { - return false; - } - } - - $this->_dirtree = array(); - // {{{ really commit the transaction - foreach ($this->file_operations as $i => $tr) { - if (!$tr) { - // support removal of non-existing backups - continue; - } - - list($type, $data) = $tr; - switch ($type) { - case 'backup': - if (!file_exists($data[0])) { - $this->file_operations[$i] = false; - break; - } - - if (!@copy($data[0], $data[0] . '.bak')) { - $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . - '.bak ' . $php_errormsg); - return false; - } - $this->log(3, "+ backup $data[0] to $data[0].bak"); - break; - case 'removebackup': - if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { - unlink($data[0] . '.bak'); - $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); - } - break; - case 'rename': - $test = file_exists($data[1]) ? @unlink($data[1]) : null; - if (!$test && file_exists($data[1])) { - if ($data[2]) { - $extra = ', this extension must be installed manually. Rename to "' . - basename($data[1]) . '"'; - } else { - $extra = ''; - } - - if (!isset($this->_options['soft'])) { - $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . - $data[0] . $extra); - } - - if (!isset($this->_options['ignore-errors'])) { - return false; - } - } - - // permissions issues with rename - copy() is far superior - $perms = @fileperms($data[0]); - if (!@copy($data[0], $data[1])) { - $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . - ' ' . $php_errormsg); - return false; - } - - // copy over permissions, otherwise they are lost - @chmod($data[1], $perms); - @unlink($data[0]); - $this->log(3, "+ mv $data[0] $data[1]"); - break; - case 'chmod': - if (!@chmod($data[1], $data[0])) { - $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . - decoct($data[0]) . ' ' . $php_errormsg); - return false; - } - - $octmode = decoct($data[0]); - $this->log(3, "+ chmod $octmode $data[1]"); - break; - case 'delete': - if (file_exists($data[0])) { - if (!@unlink($data[0])) { - $this->log(1, 'Could not delete ' . $data[0] . ' ' . - $php_errormsg); - return false; - } - $this->log(3, "+ rm $data[0]"); - } - break; - case 'rmdir': - if (file_exists($data[0])) { - do { - $testme = opendir($data[0]); - while (false !== ($entry = readdir($testme))) { - if ($entry == '.' || $entry == '..') { - continue; - } - closedir($testme); - break 2; // this directory is not empty and can't be - // deleted - } - - closedir($testme); - if (!@rmdir($data[0])) { - $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . - $php_errormsg); - return false; - } - $this->log(3, "+ rmdir $data[0]"); - } while (false); - } - break; - case 'installed_as': - $this->pkginfo->setInstalledAs($data[0], $data[1]); - if (!isset($this->_dirtree[dirname($data[1])])) { - $this->_dirtree[dirname($data[1])] = true; - $this->pkginfo->setDirtree(dirname($data[1])); - - while(!empty($data[3]) && dirname($data[3]) != $data[3] && - $data[3] != '/' && $data[3] != '\\') { - $this->pkginfo->setDirtree($pp = - $this->_prependPath($data[3], $data[2])); - $this->_dirtree[$pp] = true; - $data[3] = dirname($data[3]); - } - } - break; - } - } - // }}} - $this->log(2, "successfully committed $n file operations"); - $this->file_operations = array(); - return true; - } - - // }}} - // {{{ rollbackFileTransaction() - - function rollbackFileTransaction() - { - $n = count($this->file_operations); - $this->log(2, "rolling back $n file operations"); - foreach ($this->file_operations as $tr) { - list($type, $data) = $tr; - switch ($type) { - case 'backup': - if (file_exists($data[0] . '.bak')) { - if (file_exists($data[0] && is_writable($data[0]))) { - unlink($data[0]); - } - @copy($data[0] . '.bak', $data[0]); - $this->log(3, "+ restore $data[0] from $data[0].bak"); - } - break; - case 'removebackup': - if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { - unlink($data[0] . '.bak'); - $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); - } - break; - case 'rename': - @unlink($data[0]); - $this->log(3, "+ rm $data[0]"); - break; - case 'mkdir': - @rmdir($data[0]); - $this->log(3, "+ rmdir $data[0]"); - break; - case 'chmod': - break; - case 'delete': - break; - case 'installed_as': - $this->pkginfo->setInstalledAs($data[0], false); - break; - } - } - $this->pkginfo->resetDirtree(); - $this->file_operations = array(); - } - - // }}} - // {{{ mkDirHier($dir) - - function mkDirHier($dir) - { - $this->addFileOperation('mkdir', array($dir)); - return parent::mkDirHier($dir); - } - - // }}} - // {{{ download() - - /** - * Download any files and their dependencies, if necessary - * - * @param array a mixed list of package names, local files, or package.xml - * @param PEAR_Config - * @param array options from the command line - * @param array this is the array that will be populated with packages to - * install. Format of each entry: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @param array this will be populated with any error messages - * @param false private recursion variable - * @param false private recursion variable - * @param false private recursion variable - * @deprecated in favor of PEAR_Downloader - */ - function download($packages, $options, &$config, &$installpackages, - &$errors, $installed = false, $willinstall = false, $state = false) - { - // trickiness: initialize here - parent::PEAR_Downloader($this->ui, $options, $config); - $ret = parent::download($packages); - $errors = $this->getErrorMsgs(); - $installpackages = $this->getDownloadedPackages(); - trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . - "in favor of PEAR_Downloader class", E_USER_WARNING); - return $ret; - } - - // }}} - // {{{ _parsePackageXml() - - function _parsePackageXml(&$descfile, &$tmpdir) - { - if (substr($descfile, -4) == '.xml') { - $tmpdir = false; - } else { - // {{{ Decompress pack in tmp dir ------------------------------------- - - // To allow relative package file names - $descfile = realpath($descfile); - - if (PEAR::isError($tmpdir = System::mktemp('-d'))) { - return $tmpdir; - } - $this->log(3, '+ tmp dir created at ' . $tmpdir); - // }}} - } - - // Parse xml file ----------------------------------------------- - $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($p)) { - if (is_array($p->getUserInfo())) { - foreach ($p->getUserInfo() as $err) { - $loglevel = $err['level'] == 'error' ? 0 : 1; - if (!isset($this->_options['soft'])) { - $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); - } - } - } - return $this->raiseError('Installation failed: invalid package file'); - } - - $descfile = $p->getPackageFile(); - return $p; - } - - // }}} - /** - * Set the list of PEAR_Downloader_Package objects to allow more sane - * dependency validation - * @param array - */ - function setDownloadedPackages(&$pkgs) - { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($pkgs); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - return $err; - } - $this->_downloadedPackages = &$pkgs; - } - - /** - * Set the list of PEAR_Downloader_Package objects to allow more sane - * dependency validation - * @param array - */ - function setUninstallPackages(&$pkgs) - { - $this->_downloadedPackages = &$pkgs; - } - - function getInstallPackages() - { - return $this->_downloadedPackages; - } - - // {{{ install() - - /** - * Installs the files within the package file specified. - * - * @param string|PEAR_Downloader_Package $pkgfile path to the package file, - * or a pre-initialized packagefile object - * @param array $options - * recognized options: - * - installroot : optional prefix directory for installation - * - force : force installation - * - register-only : update registry but don't install files - * - upgrade : upgrade existing install - * - soft : fail silently - * - nodeps : ignore dependency conflicts/missing dependencies - * - alldeps : install all dependencies - * - onlyreqdeps : install only required dependencies - * - * @return array|PEAR_Error package info if successful - */ - function install($pkgfile, $options = array()) - { - $this->_options = $options; - $this->_registry = &$this->config->getRegistry(); - if (is_object($pkgfile)) { - $dlpkg = &$pkgfile; - $pkg = $pkgfile->getPackageFile(); - $pkgfile = $pkg->getArchiveFile(); - $descfile = $pkg->getPackageFile(); - $tmpdir = dirname($descfile); - } else { - $descfile = $pkgfile; - $tmpdir = ''; - $pkg = $this->_parsePackageXml($descfile, $tmpdir); - if (PEAR::isError($pkg)) { - return $pkg; - } - } - - if (realpath($descfile) != realpath($pkgfile)) { - $tar = new Archive_Tar($pkgfile); - if (!$tar->extract($tmpdir)) { - return $this->raiseError("unable to unpack $pkgfile"); - } - } - - $pkgname = $pkg->getName(); - $channel = $pkg->getChannel(); - if (isset($this->_options['packagingroot'])) { - $regdir = $this->_prependPath( - $this->config->get('php_dir', null, 'pear.php.net'), - $this->_options['packagingroot']); - - $packrootphp_dir = $this->_prependPath( - $this->config->get('php_dir', null, $channel), - $this->_options['packagingroot']); - } - - if (isset($options['installroot'])) { - $this->config->setInstallRoot($options['installroot']); - $this->_registry = &$this->config->getRegistry(); - $installregistry = &$this->_registry; - $this->installroot = ''; // all done automagically now - $php_dir = $this->config->get('php_dir', null, $channel); - } else { - $this->config->setInstallRoot(false); - $this->_registry = &$this->config->getRegistry(); - if (isset($this->_options['packagingroot'])) { - $installregistry = &new PEAR_Registry($regdir); - if (!$installregistry->channelExists($channel, true)) { - // we need to fake a channel-discover of this channel - $chanobj = $this->_registry->getChannel($channel, true); - $installregistry->addChannel($chanobj); - } - $php_dir = $packrootphp_dir; - } else { - $installregistry = &$this->_registry; - $php_dir = $this->config->get('php_dir', null, $channel); - } - $this->installroot = ''; - } - - // {{{ checks to do when not in "force" mode - if (empty($options['force']) && - (file_exists($this->config->get('php_dir')) && - is_dir($this->config->get('php_dir')))) { - $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); - $instfilelist = $pkg->getInstallationFileList(true); - if (PEAR::isError($instfilelist)) { - return $instfilelist; - } - - // ensure we have the most accurate registry - $installregistry->flushFileMap(); - $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); - if (PEAR::isError($test)) { - return $test; - } - - if (sizeof($test)) { - $pkgs = $this->getInstallPackages(); - $found = false; - foreach ($pkgs as $param) { - if ($pkg->isSubpackageOf($param)) { - $found = true; - break; - } - } - - if ($found) { - // subpackages can conflict with earlier versions of parent packages - $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_array($info)) { - if (strtolower($info[1]) == strtolower($param->getPackage()) && - strtolower($info[0]) == strtolower($param->getChannel()) - ) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } - - unset($test[$file]); - } - } else { - if (strtolower($param->getChannel()) != 'pear.php.net') { - continue; - } - - if (strtolower($info) == strtolower($param->getPackage())) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } - - unset($test[$file]); - } - } - } - - $pfk = &new PEAR_PackageFile($this->config); - $parentpkg = &$pfk->fromArray($parentreg); - $installregistry->updatePackage2($parentpkg); - } - - if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_string($info)) { - // pear.php.net packages are always stored as strings - if (strtolower($info) == strtolower($param->getPackage())) { - // upgrading existing package - unset($test[$file]); - } - } - } - } - - if (count($test)) { - $msg = "$channel/$pkgname: conflicting files found:\n"; - $longest = max(array_map("strlen", array_keys($test))); - $fmt = "%${longest}s (%s)\n"; - foreach ($test as $file => $info) { - if (!is_array($info)) { - $info = array('pear.php.net', $info); - } - $info = $info[0] . '/' . $info[1]; - $msg .= sprintf($fmt, $file, $info); - } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError($msg); - } - - if (!isset($options['soft'])) { - $this->log(0, "WARNING: $msg"); - } - } - } - } - // }}} - - $this->startFileTransaction(); - - if (empty($options['upgrade']) && empty($options['soft'])) { - // checks to do only when installing new packages - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if (empty($options['force']) && $test) { - return $this->raiseError("$channel/$pkgname is already installed"); - } - } else { - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if ($test) { - $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $v2 = $pkg->getVersion(); - $cmp = version_compare("$v1", "$v2", 'gt'); - if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { - return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); - } - - if (empty($options['register-only'])) { - // when upgrading, remove old release's files first: - if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, - true))) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - $backedup = $err; - } - } - } - } - - // {{{ Copy files to dest dir --------------------------------------- - - // info from the package it self we want to access from _installFile - $this->pkginfo = &$pkg; - // used to determine whether we should build any C code - $this->source_files = 0; - - $savechannel = $this->config->get('default_channel'); - if (empty($options['register-only']) && !is_dir($php_dir)) { - if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { - return $this->raiseError("no installation destination directory '$php_dir'\n"); - } - } - - $tmp_path = dirname($descfile); - if (substr($pkgfile, -4) != '.xml') { - $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); - } - - $this->configSet('default_channel', $channel); - // {{{ install files - - $ver = $pkg->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - $filelist = $pkg->getInstallationFilelist(); - } else { - $filelist = $pkg->getFileList(); - } - - if (PEAR::isError($filelist)) { - return $filelist; - } - - $p = &$installregistry->getPackage($pkgname, $channel); - $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false; - - $pkg->resetFilelist(); - $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), - 'version', $pkg->getChannel())); - foreach ($filelist as $file => $atts) { - $this->expectError(PEAR_INSTALLER_FAILED); - if ($pkg->getPackagexmlVersion() == '1.0') { - $res = $this->_installFile($file, $atts, $tmp_path, $options); - } else { - $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); - } - $this->popExpect(); - - if (PEAR::isError($res)) { - if (empty($options['ignore-errors'])) { - $this->rollbackFileTransaction(); - if ($res->getMessage() == "file does not exist") { - $this->raiseError("file $file in package.xml does not exist"); - } - - return $this->raiseError($res); - } - - if (!isset($options['soft'])) { - $this->log(0, "Warning: " . $res->getMessage()); - } - } - - $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; - if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { - // Register files that were installed - $pkg->installedFile($file, $atts); - } - } - // }}} - - // {{{ compile and install source files - if ($this->source_files > 0 && empty($options['nobuild'])) { - if (PEAR::isError($err = - $this->_compileSourceFiles($savechannel, $pkg))) { - return $err; - } - } - // }}} - - if (isset($backedup)) { - $this->_removeBackups($backedup); - } - - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); - } - // }}} - - $ret = false; - $installphase = 'install'; - $oldversion = false; - // {{{ Register that the package is installed ----------------------- - if (empty($options['upgrade'])) { - // if 'force' is used, replace the info in registry - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if (!empty($options['force']) && $test) { - $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $installregistry->deletePackage($pkgname, $usechannel); - } - $ret = $installregistry->addPackage2($pkg); - } else { - if ($dirtree) { - $this->startFileTransaction(); - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - $this->commitFileTransaction(); - } - - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - // new: upgrade installs a package if it isn't installed - if (!$test) { - $ret = $installregistry->addPackage2($pkg); - } else { - if ($usechannel != $channel) { - $installregistry->deletePackage($pkgname, $usechannel); - $ret = $installregistry->addPackage2($pkg); - } else { - $ret = $installregistry->updatePackage2($pkg); - } - $installphase = 'upgrade'; - } - } - - if (!$ret) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError("Adding package $channel/$pkgname to registry failed"); - } - // }}} - - $this->configSet('default_channel', $savechannel); - if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist - if (PEAR_Task_Common::hasPostinstallTasks()) { - PEAR_Task_Common::runPostinstallTasks($installphase); - } - } - - return $pkg->toArray(true); - } - - // }}} - - // {{{ _compileSourceFiles() - /** - * @param string - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function _compileSourceFiles($savechannel, &$filelist) - { - require_once 'phar://go-pear.phar/' . 'PEAR/Builder.php'; - $this->log(1, "$this->source_files source files, building"); - $bob = &new PEAR_Builder($this->ui); - $bob->debug = $this->debug; - $built = $bob->build($filelist, array(&$this, '_buildCallback')); - if (PEAR::isError($built)) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $built; - } - - $this->log(1, "\nBuild process completed successfully"); - foreach ($built as $ext) { - $bn = basename($ext['file']); - list($_ext_name, $_ext_suff) = explode('.', $bn); - if ($_ext_suff == '.so' || $_ext_suff == '.dll') { - if (extension_loaded($_ext_name)) { - $this->raiseError("Extension '$_ext_name' already loaded. " . - 'Please unload it in your php.ini file ' . - 'prior to install or upgrade'); - } - $role = 'ext'; - } else { - $role = 'src'; - } - - $dest = $ext['dest']; - $packagingroot = ''; - if (isset($this->_options['packagingroot'])) { - $packagingroot = $this->_options['packagingroot']; - } - - $copyto = $this->_prependPath($dest, $packagingroot); - $extra = $copyto != $dest ? " as '$copyto'" : ''; - $this->log(1, "Installing '$dest'$extra"); - - $copydir = dirname($copyto); - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (!file_exists($copydir) || !is_dir($copydir)) { - if (!$this->mkDirHier($copydir)) { - return $this->raiseError("failed to mkdir $copydir", - PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ mkdir $copydir"); - } - - if (!@copy($ext['file'], $copyto)) { - return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); - } - - $this->log(3, "+ cp $ext[file] $copyto"); - $this->addFileOperation('rename', array($ext['file'], $copyto)); - if (!OS_WINDOWS) { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - $this->addFileOperation('chmod', array($mode, $copyto)); - if (!@chmod($copyto, $mode)) { - $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); - } - } - } - - - $data = array( - 'role' => $role, - 'name' => $bn, - 'installed_as' => $dest, - 'php_api' => $ext['php_api'], - 'zend_mod_api' => $ext['zend_mod_api'], - 'zend_ext_api' => $ext['zend_ext_api'], - ); - - if ($filelist->getPackageXmlVersion() == '1.0') { - $filelist->installedFile($bn, $data); - } else { - $filelist->installedFile($bn, array('attribs' => $data)); - } - } - } - - // }}} - function &getUninstallPackages() - { - return $this->_downloadedPackages; - } - // {{{ uninstall() - - /** - * Uninstall a package - * - * This method removes all files installed by the application, and then - * removes any empty directories. - * @param string package name - * @param array Command-line options. Possibilities include: - * - * - installroot: base installation dir, if not the default - * - register-only : update registry but don't remove files - * - nodeps: do not process dependencies of other packages to ensure - * uninstallation does not break things - */ - function uninstall($package, $options = array()) - { - $installRoot = isset($options['installroot']) ? $options['installroot'] : ''; - $this->config->setInstallRoot($installRoot); - - $this->installroot = ''; - $this->_registry = &$this->config->getRegistry(); - if (is_object($package)) { - $channel = $package->getChannel(); - $pkg = $package; - $package = $pkg->getPackage(); - } else { - $pkg = false; - $info = $this->_registry->parsePackageName($package, - $this->config->get('default_channel')); - $channel = $info['channel']; - $package = $info['package']; - } - - $savechannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $channel); - if (!is_object($pkg)) { - $pkg = $this->_registry->getPackage($package, $channel); - } - - if (!$pkg) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError($this->_registry->parsedPackageNameToString( - array( - 'channel' => $channel, - 'package' => $package - ), true) . ' not installed'); - } - - if ($pkg->getInstalledBinary()) { - // this is just an alias for a binary package - return $this->_registry->deletePackage($package, $channel); - } - - $filelist = $pkg->getFilelist(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - - $depchecker = &new PEAR_Dependency2($this->config, $options, - array('channel' => $channel, 'package' => $package), - PEAR_VALIDATE_UNINSTALLING); - $e = $depchecker->validatePackageUninstall($this); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($e); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $e->getMessage()); - } - } elseif (is_array($e)) { - if (!isset($options['soft'])) { - $this->log(0, $e[0]); - } - } - - $this->pkginfo = &$pkg; - // pretty much nothing happens if we are only registering the uninstall - if (empty($options['register-only'])) { - // {{{ Delete the files - $this->startFileTransaction(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { - PEAR::popErrorHandling(); - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - PEAR::popErrorHandling(); - } - - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } - } else { - $this->startFileTransaction(); - $dirtree = $pkg->getDirTree(); - if ($dirtree === false) { - $this->configSet('default_channel', $savechannel); - return $this->_registry->deletePackage($package, $channel); - } - - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } - - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } - } - } - // }}} - } - - $this->configSet('default_channel', $savechannel); - // Register that the package is no longer installed - return $this->_registry->deletePackage($package, $channel); - } - - /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * It also removes duplicate dependencies - * @param array an array of PEAR_PackageFile_v[1/2] objects - * @return array|PEAR_Error array of array(packagefilename, package.xml contents) - */ - function sortPackagesForUninstall(&$packages) - { - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); - if (PEAR::isError($this->_dependencyDB)) { - return $this->_dependencyDB; - } - usort($packages, array(&$this, '_sortUninstall')); - } - - function _sortUninstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return -1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return 1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependencyDB->dependsOn($a, $b)) { - return -1; - } - if ($this->_dependencyDB->dependsOn($b, $a)) { - return 1; - } - return 0; - } - - // }}} - // {{{ _sortDirs() - function _sortDirs($a, $b) - { - if (strnatcmp($a, $b) == -1) return 1; - if (strnatcmp($a, $b) == 1) return -1; - return 0; - } - - // }}} - - // {{{ _buildCallback() - - function _buildCallback($what, $data) - { - if (($what == 'cmdoutput' && $this->debug > 1) || - ($what == 'output' && $this->debug > 0)) { - $this->ui->outputData(rtrim($data), 'build'); - } - } - - // }}} -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Role.php 278552 2009-04-10 19:42:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base class for installer roles - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role/Common.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role -{ - /** - * Set up any additional configuration variables that file roles require - * - * Never call this directly, it is called by the PEAR_Config constructor - * @param PEAR_Config - * @access private - * @static - */ - function initializeConfig(&$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { - if (!$info['config_vars']) { - continue; - } - - $config->_addConfigVars($class, $info['config_vars']); - } - } - - /** - * @param PEAR_PackageFile_v2 - * @param string role name - * @param PEAR_Config - * @return PEAR_Installer_Role_Common - * @static - */ - function &factory($pkg, $role, &$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { - $a = false; - return $a; - } - - $a = 'PEAR_Installer_Role_' . ucfirst($role); - if (!class_exists($a)) { - require_once 'phar://go-pear.phar/' . str_replace('_', '/', $a) . '.php'; - } - - $b = new $a($config); - return $b; - } - - /** - * Get a list of file roles that are valid for the particular release type. - * - * For instance, src files serve no purpose in regular php releases. - * @param string - * @param bool clear cache - * @return array - * @static - */ - function getValidRoles($release, $clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret = array(); - if ($clear) { - $ret = array(); - } - - if (isset($ret[$release])) { - return $ret[$release]; - } - - $ret[$release] = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if (in_array($release, $okreleases['releasetypes'])) { - $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret[$release]; - } - - /** - * Get a list of roles that require their files to be installed - * - * Most roles must be installed, but src and package roles, for instance - * are pseudo-roles. src files are compiled into a new extension. Package - * roles are actually fully bundled releases of a package - * @param bool clear cache - * @return array - * @static - */ - function getInstallableRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['installable']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of roles that are affected by the baseinstalldir attribute - * - * Most roles ignore this attribute, and instead install directly into: - * PackageName/filepath - * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php - * @param bool clear cache - * @return array - * @static - */ - function getBaseinstallRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['honorsbaseinstall']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of file roles that should be analyzed for PHP content at package time, - * like the "php" role. - * @param bool clear cache - * @return array - * @static - */ - function getPhpRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['phpfile']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * @param string which directory to look for classes, defaults to - * the Installer/Roles subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * @access public - * @static - */ - function registerRoles($dir = null) - { - $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Role'; - } - - if (!file_exists($dir) || !is_dir($dir)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); - } - - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); - } - - while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.xml') { - continue; - } - - $class = "PEAR_Installer_Role_".substr($entry, 0, -4); - // List of roles - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { - $file = "$dir/$entry"; - $parser->parse(file_get_contents($file)); - $data = $parser->getData(); - if (!is_array($data['releasetypes'])) { - $data['releasetypes'] = array($data['releasetypes']); - } - - $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; - } - } - - closedir($dp); - ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); - PEAR_Installer_Role::getBaseinstallRoles(true); - PEAR_Installer_Role::getInstallableRoles(true); - PEAR_Installer_Role::getPhpRoles(true); - PEAR_Installer_Role::getValidRoles('****', true); - return true; - } -} - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class for all installation roles. - * - * This class allows extensibility of file roles. Packages with complex - * customization can now provide custom file roles along with the possibility of - * adding configuration values to match. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Common -{ - /** - * @var PEAR_Config - * @access protected - */ - var $config; - - /** - * @param PEAR_Config - */ - function PEAR_Installer_Role_Common(&$config) - { - $this->config = $config; - } - - /** - * Retrieve configuration information about a file role from its XML info - * - * @param string $role Role Classname, as in "PEAR_Installer_Role_Data" - * @return array - */ - function getInfo($role) - { - if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) { - return PEAR::raiseError('Unknown Role class: "' . $role . '"'); - } - return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role]; - } - - /** - * This is called for each file to set up the directories and files - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array attributes from the tag - * @param string file name - * @return array an array consisting of: - * - * 1 the original, pre-baseinstalldir installation directory - * 2 the final installation directory - * 3 the full path to the final location of the file - * 4 the location of the pre-installation file - */ - function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - if (!$roleInfo['locationconfig']) { - return false; - } - if ($roleInfo['honorsbaseinstall']) { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer, - $pkg->getChannel()); - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - } elseif ($roleInfo['unusualbaseinstall']) { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], - $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - } else { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], - $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); - } - if (dirname($file) != '.' && empty($atts['install-as'])) { - $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); - } - if (empty($atts['install-as'])) { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); - } else { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; - } - $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; - - // Clean up the DIRECTORY_SEPARATOR mess - $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; - - list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR), - array($dest_dir, $dest_file, $orig_file)); - return array($save_destdir, $dest_dir, $dest_file, $orig_file); - } - - /** - * Get the name of the configuration variable that specifies the location of this file - * @return string|false - */ - function getLocationConfig() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['locationconfig']; - } - - /** - * Do any unusual setup here - * @param PEAR_Installer - * @param PEAR_PackageFile_v2 - * @param array file attributes - * @param string file name - */ - function setup(&$installer, $pkg, $atts, $file) - { - } - - function isExecutable() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['executable']; - } - - function isInstallable() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['installable']; - } - - function isExtension() - { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['phpextension']; - } -} -?> - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Data.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - data_dir - - - - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Doc.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - doc_dir - - - - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Php.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - php_dir - 1 - - 1 - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Script.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - bin_dir - 1 - - - 1 - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Test.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - test_dir - - - - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PackageFile.php 286670 2009-08-02 14:16:06Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php'; -/** - * Error code if the package.xml tag does not contain a valid version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); -/** - * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, - * currently - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); -/** - * Abstraction for the package.xml package description file - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile -{ - /** - * @var PEAR_Config - */ - var $_config; - var $_debug; - /** - * Temp directory for uncompressing tgz files. - * @var string|false - */ - var $_tmpdir; - var $_logger = false; - /** - * @var boolean - */ - var $_rawReturn = false; - - /** - * - * @param PEAR_Config $config - * @param ? $debug - * @param string @tmpdir Optional temporary directory for uncompressing - * files - */ - function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) - { - $this->_config = $config; - $this->_debug = $debug; - $this->_tmpdir = $tmpdir; - } - - /** - * Turn off validation - return a parsed package.xml without checking it - * - * This is used by the package-validate command - */ - function rawReturn() - { - $this->_rawReturn = true; - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - /** - * Create a PEAR_PackageFile_Parser_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 - */ - function &parserFactory($version) - { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } - - include_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; - $version = $version{0}; - $class = "PEAR_PackageFile_Parser_v$version"; - $a = new $class; - return $a; - } - - /** - * For simpler unit-testing - * @return string - */ - function getClassPrefix() - { - return 'PEAR_PackageFile_v'; - } - - /** - * Create a PEAR_PackageFile_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 - */ - function &factory($version) - { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } - - include_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v' . $version{0} . '.php'; - $version = $version{0}; - $class = $this->getClassPrefix() . $version; - $a = new $class; - return $a; - } - - /** - * Create a PEAR_PackageFile_v* from its toArray() method - * - * WARNING: no validation is performed, the array is assumed to be valid, - * always parse from xml if you want validation. - * @param array $arr - * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 - * @uses factory() to construct the returned object. - */ - function &fromArray($arr) - { - if (isset($arr['xsdversion'])) { - $obj = &$this->factory($arr['xsdversion']); - if ($this->_logger) { - $obj->setLogger($this->_logger); - } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; - } - - if (isset($arr['package']['attribs']['version'])) { - $obj = &$this->factory($arr['package']['attribs']['version']); - } else { - $obj = &$this->factory('1.0'); - } - - if ($this->_logger) { - $obj->setLogger($this->_logger); - } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; - } - - /** - * Create a PEAR_PackageFile_v* from an XML string. - * @access public - * @param string $data contents of package.xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string $file full path to the package.xml file (and the files - * it references) - * @param string $archive optional name of the archive that the XML was - * extracted from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses parserFactory() to construct a parser to load the package. - */ - function &fromXmlString($data, $state, $file, $archive = false) - { - if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { - if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { - return PEAR::raiseError('package.xml version "' . $packageversion[1] . - '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); - } - - $object = &$this->parserFactory($packageversion[1]); - if ($this->_logger) { - $object->setLogger($this->_logger); - } - - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } - - if ($this->_rawReturn) { - return $pf; - } - - if (!$pf->validate($state)) {; - if ($this->_config->get('verbose') > 0 - && $this->_logger && $pf->getValidationWarnings(false) - ) { - foreach ($pf->getValidationWarnings(false) as $warning) { - $this->_logger->log(0, 'ERROR: ' . $warning['message']); - } - } - - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } - - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } - } - - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 - } - - return $pf; - } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) { - $a = PEAR::raiseError('package.xml file "' . $file . - '" has unsupported package.xml version "' . $packageversion[1] . '"'); - return $a; - } else { - if (!class_exists('PEAR_ErrorStack')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php'; - } - - PEAR_ErrorStack::staticPush('PEAR_PackageFile', - PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, - 'warning', array('xml' => $data), 'package.xml "' . $file . - '" has no package.xml version'); - $object = &$this->parserFactory('1.0'); - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } - - if ($this->_rawReturn) { - return $pf; - } - - if (!$pf->validate($state)) { - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } - - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } - } - - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 - } - - return $pf; - } - } - - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * @return void - */ - function addTempFile($file) - { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; - } - - /** - * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. - * @access public - * @param string contents of package.xml file - * @param int package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @using Archive_Tar to extract the files - * @using fromPackageFile() to load the package after the package.xml - * file is extracted. - */ - function &fromTgzFile($file, $state) - { - if (!class_exists('Archive_Tar')) { - require_once 'phar://go-pear.phar/' . 'Archive/Tar.php'; - } - - $tar = new Archive_Tar($file); - if ($this->_debug <= 1) { - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - } - - $content = $tar->listContent(); - if ($this->_debug <= 1) { - $tar->popErrorHandling(); - } - - if (!is_array($content)) { - if (is_string($file) && strlen($file < 255) && - (!file_exists($file) || !@is_file($file))) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } - - $file = realpath($file); - $ret = PEAR::raiseError("Could not get contents of package \"$file\"". - '. Invalid tgz file.'); - return $ret; - } - - if (!count($content) && !@is_file($file)) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } - - $xml = null; - $origfile = $file; - foreach ($content as $file) { - $name = $file['filename']; - if ($name == 'package2.xml') { // allow a .tgz to distribute both versions - $xml = $name; - break; - } - - if ($name == 'package.xml') { - $xml = $name; - break; - } elseif (preg_match('/package.xml$/', $name, $match)) { - $xml = $name; - break; - } - } - - if ($this->_tmpdir) { - $tmpdir = $this->_tmpdir; - } else { - $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); - if ($tmpdir === false) { - $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); - return $ret; - } - - PEAR_PackageFile::addTempFile($tmpdir); - } - - $this->_extractErrors(); - PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); - if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { - $extra = implode("\n", $this->_extractErrors()); - if ($extra) { - $extra = ' ' . $extra; - } - - PEAR::staticPopErrorHandling(); - $ret = PEAR::raiseError('could not extract the package.xml file from "' . - $origfile . '"' . $extra); - return $ret; - } - - PEAR::staticPopErrorHandling(); - $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); - return $ret; - } - - /** - * helper for extracting Archive_Tar errors - * @var array - * @access private - */ - var $_extractErrors = array(); - - /** - * helper callback for extracting Archive_Tar errors - * - * @param PEAR_Error|null $err - * @return array - * @access private - */ - function _extractErrors($err = null) - { - static $errors = array(); - if ($err === null) { - $e = $errors; - $errors = array(); - return $e; - } - $errors[] = $err->getMessage(); - } - - /** - * Create a PEAR_PackageFile_v* from a package.xml file. - * - * @access public - * @param string $descfile name of package xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string|false $archive name of the archive this package.xml came - * from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses PEAR_PackageFile::fromXmlString to create the oject after the - * XML is loaded from the package.xml file. - */ - function &fromPackageFile($descfile, $state, $archive = false) - { - $fp = false; - if (is_string($descfile) && strlen($descfile) < 255 && - ( - !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) - || (!$fp = @fopen($descfile, 'r')) - ) - ) { - $a = PEAR::raiseError("Unable to open $descfile"); - return $a; - } - - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); - return $ret; - } - - - /** - * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. - * - * This method is able to extract information about a package from a .tgz - * archive or from a XML package definition file. - * - * @access public - * @param string $info file name - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses fromPackageFile() if the file appears to be XML - * @uses fromTgzFile() to load all non-XML files - */ - function &fromAnyFile($info, $state) - { - if (is_dir($info)) { - $dir_name = realpath($info); - if (file_exists($dir_name . '/package.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); - } elseif (file_exists($dir_name . '/package2.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); - } else { - $info = PEAR::raiseError("No package definition found in '$info' directory"); - } - - return $info; - } - - $fp = false; - if (is_string($info) && strlen($info) < 255 && - (file_exists($info) || ($fp = @fopen($info, 'r'))) - ) { - - if ($fp) { - fclose($fp); - } - - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = &PEAR_PackageFile::fromPackageFile($info, $state); - } elseif ($tmp == '.tar' || $tmp == '.tgz') { - $info = &PEAR_PackageFile::fromTgzFile($info, $state); - } else { - $fp = fopen($info, 'r'); - $test = fread($fp, 5); - fclose($fp); - if ($test == ' - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php 286494 2009-07-29 06:57:11Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php'; -require_once 'phar://go-pear.phar/' . 'System.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; -/** - * This class converts a PEAR_PackageFile_v1 object into any output format. - * - * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 - * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Generator_v1 -{ - /** - * @var PEAR_PackageFile_v1 - */ - var $_packagefile; - function PEAR_PackageFile_Generator_v1(&$packagefile) - { - $this->_packagefile = &$packagefile; - } - - function getPackagerVersion() - { - return '1.9.0'; - } - - /** - * @param PEAR_Packager - * @param bool if true, a .tgz is written, otherwise a .tar is written - * @param string|null directory in which to save the .tgz - * @return string|PEAR_Error location of package or error object - */ - function toTgz(&$packager, $compress = true, $where = null) - { - require_once 'phar://go-pear.phar/' . 'Archive/Tar.php'; - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . - ' not be created'); - } - if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && - !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . - ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); - } - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); - } - $pkginfo = $this->_packagefile->getArray(); - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; - if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && - !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . - getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); - } - if ($pkgfile = $this->_packagefile->getPackageFile()) { - $pkgdir = dirname(realpath($pkgfile)); - $pkgfile = basename($pkgfile); - } else { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' . - 'be created from a real file'); - } - // {{{ Create the package file list - $filelist = array(); - $i = 0; - - foreach ($this->_packagefile->getFilelist() as $fname => $atts) { - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return PEAR::raiseError("File does not exist: $fname"); - } else { - $filelist[$i++] = $file; - if (!isset($atts['md5sum'])) { - $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file)); - } - $packager->log(2, "Adding file $fname"); - } - } - // }}} - $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); - if ($packagexml) { - $tar =& new Archive_Tar($dest_package, $compress); - $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors - // ----- Creates with the package.xml file - $ok = $tar->createModify(array($packagexml), '', $where); - if (PEAR::isError($ok)) { - return $ok; - } elseif (!$ok) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); - } - // ----- Add the content of the package - if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); - } - return $dest_package; - } - } - - /** - * @param string|null directory to place the package.xml in, or null for a temporary dir - * @param int one of the PEAR_VALIDATE_* constants - * @param string name of the generated file - * @param bool if true, then no analysis will be performed on role="php" files - * @return string|PEAR_Error path to the created file on success - */ - function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml', - $nofilechecking = false) - { - if (!$this->_packagefile->validate($state, $nofilechecking)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml', - null, null, null, $this->_packagefile->getValidationWarnings()); - } - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' . - ' not be created'); - } - $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; - $np = @fopen($newpkgfile, 'wb'); - if (!$np) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' . - "$name as $newpkgfile"); - } - fwrite($np, $this->toXml($state, true)); - fclose($np); - return $newpkgfile; - } - - /** - * fix both XML encoding to be UTF8, and replace standard XML entities < > " & ' - * - * @param string $string - * @return string - * @access private - */ - function _fixXmlEncoding($string) - { - if (version_compare(phpversion(), '5.0.0', 'lt')) { - $string = utf8_encode($string); - } - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - '\'' => ''' )); - } - - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @return string XML data - */ - function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false) - { - $this->_packagefile->setDate(date('Y-m-d')); - if (!$this->_packagefile->validate($state, $nofilevalidation)) { - return false; - } - $pkginfo = $this->_packagefile->getArray(); - static $maint_map = array( - "handle" => "user", - "name" => "name", - "email" => "email", - "role" => "role", - ); - $ret = "\n"; - $ret .= "\n"; - $ret .= "\n" . -" $pkginfo[package]"; - if (isset($pkginfo['extends'])) { - $ret .= "\n$pkginfo[extends]"; - } - $ret .= - "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" . -" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" . -" \n"; - foreach ($pkginfo['maintainers'] as $maint) { - $ret .= " \n"; - foreach ($maint_map as $idx => $elm) { - $ret .= " <$elm>"; - $ret .= $this->_fixXmlEncoding($maint[$idx]); - $ret .= "\n"; - } - $ret .= " \n"; - } - $ret .= " \n"; - $ret .= $this->_makeReleaseXml($pkginfo, false, $state); - if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) { - $ret .= " \n"; - foreach ($pkginfo['changelog'] as $oldrelease) { - $ret .= $this->_makeReleaseXml($oldrelease, true); - } - $ret .= " \n"; - } - $ret .= "\n"; - return $ret; - } - - // }}} - // {{{ _makeReleaseXml() - - /** - * Generate part of an XML description with release information. - * - * @param array $pkginfo array with release information - * @param bool $changelog whether the result will be in a changelog element - * - * @return string XML data - * - * @access private - */ - function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL) - { - // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! - $indent = $changelog ? " " : ""; - $ret = "$indent \n"; - if (!empty($pkginfo['version'])) { - $ret .= "$indent $pkginfo[version]\n"; - } - if (!empty($pkginfo['release_date'])) { - $ret .= "$indent $pkginfo[release_date]\n"; - } - if (!empty($pkginfo['release_license'])) { - $ret .= "$indent $pkginfo[release_license]\n"; - } - if (!empty($pkginfo['release_state'])) { - $ret .= "$indent $pkginfo[release_state]\n"; - } - if (!empty($pkginfo['release_notes'])) { - $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes'])) - ."\n$indent \n"; - } - if (!empty($pkginfo['release_warnings'])) { - $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n"; - } - if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { - $ret .= "$indent \n"; - foreach ($pkginfo['release_deps'] as $dep) { - $ret .= "$indent _fixXmlEncoding($c['name']) . "\""; - if (isset($c['default'])) { - $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\""; - } - $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\""; - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - if (isset($pkginfo['provides'])) { - foreach ($pkginfo['provides'] as $key => $what) { - $ret .= "$indent recursiveXmlFilelist($pkginfo['filelist']); - } else { - foreach ($pkginfo['filelist'] as $file => $fa) { - if (!isset($fa['role'])) { - $fa['role'] = ''; - } - $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"'; - } - if (isset($fa['md5sum'])) { - $ret .= " md5sum=\"$fa[md5sum]\""; - } - if (isset($fa['platform'])) { - $ret .= " platform=\"$fa[platform]\""; - } - if (!empty($fa['install-as'])) { - $ret .= ' install-as="' . - $this->_fixXmlEncoding($fa['install-as']) . '"'; - } - $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; - if (empty($fa['replacements'])) { - $ret .= "/>\n"; - } else { - $ret .= ">\n"; - foreach ($fa['replacements'] as $r) { - $ret .= "$indent $v) { - $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; - } - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - } - } - $ret .= "$indent
    \n"; - } - $ret .= "$indent \n"; - return $ret; - } - - /** - * @param array - * @access protected - */ - function recursiveXmlFilelist($list) - { - $this->_dirs = array(); - foreach ($list as $file => $attributes) { - $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); - } - return $this->_formatDir($this->_dirs); - } - - /** - * @param array - * @param array - * @param string|null - * @param array|null - * @access private - */ - function _addDir(&$dirs, $dir, $file = null, $attributes = null) - { - if ($dir == array() || $dir == array('.')) { - $dirs['files'][basename($file)] = $attributes; - return; - } - $curdir = array_shift($dir); - if (!isset($dirs['dirs'][$curdir])) { - $dirs['dirs'][$curdir] = array(); - } - $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); - } - - /** - * @param array - * @param string - * @param string - * @access private - */ - function _formatDir($dirs, $indent = '', $curdir = '') - { - $ret = ''; - if (!count($dirs)) { - return ''; - } - if (isset($dirs['dirs'])) { - uksort($dirs['dirs'], 'strnatcasecmp'); - foreach ($dirs['dirs'] as $dir => $contents) { - $usedir = "$curdir/$dir"; - $ret .= "$indent \n"; - $ret .= $this->_formatDir($contents, "$indent ", $usedir); - $ret .= "$indent \n"; - } - } - if (isset($dirs['files'])) { - uksort($dirs['files'], 'strnatcasecmp'); - foreach ($dirs['files'] as $file => $attribs) { - $ret .= $this->_formatFile($file, $attribs, $indent); - } - } - return $ret; - } - - /** - * @param string - * @param array - * @param string - * @access private - */ - function _formatFile($file, $attributes, $indent) - { - $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"'; - } - if (isset($attributes['md5sum'])) { - $ret .= " md5sum=\"$attributes[md5sum]\""; - } - if (isset($attributes['platform'])) { - $ret .= " platform=\"$attributes[platform]\""; - } - if (!empty($attributes['install-as'])) { - $ret .= ' install-as="' . - $this->_fixXmlEncoding($attributes['install-as']) . '"'; - } - $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; - if (empty($attributes['replacements'])) { - $ret .= "/>\n"; - } else { - $ret .= ">\n"; - foreach ($attributes['replacements'] as $r) { - $ret .= "$indent $v) { - $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; - } - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - return $ret; - } - - // {{{ _unIndent() - - /** - * Unindent given string (?) - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } - } - return $data; - } - - /** - * @return array - */ - function dependenciesToV2() - { - $arr = array(); - $this->_convertDependencies2_0($arr); - return $arr['dependencies']; - } - - /** - * Convert a package.xml version 1.0 into version 2.0 - * - * Note that this does a basic conversion, to allow more advanced - * features like bundles and multiple releases - * @param string the classname to instantiate and return. This must be - * PEAR_PackageFile_v2 or a descendant - * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the - * strictest parameters will be converted - * @return PEAR_PackageFile_v2|PEAR_Error - */ - function &toV2($class = 'PEAR_PackageFile_v2', $strict = false) - { - if ($strict) { - if (!$this->_packagefile->validate()) { - $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' . - ' to version 2.0', null, null, null, - $this->_packagefile->getValidationWarnings(true)); - return $a; - } - } - - $arr = array( - 'attribs' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" . -"http://pear.php.net/dtd/tasks-1.0.xsd\n" . -"http://pear.php.net/dtd/package-2.0\n" . -'http://pear.php.net/dtd/package-2.0.xsd', - ), - 'name' => $this->_packagefile->getPackage(), - 'channel' => 'pear.php.net', - ); - $arr['summary'] = $this->_packagefile->getSummary(); - $arr['description'] = $this->_packagefile->getDescription(); - $maintainers = $this->_packagefile->getMaintainers(); - foreach ($maintainers as $maintainer) { - if ($maintainer['role'] != 'lead') { - continue; - } - $new = array( - 'name' => $maintainer['name'], - 'user' => $maintainer['handle'], - 'email' => $maintainer['email'], - 'active' => 'yes', - ); - $arr['lead'][] = $new; - } - - if (!isset($arr['lead'])) { // some people... you know? - $arr['lead'] = array( - 'name' => 'unknown', - 'user' => 'unknown', - 'email' => 'noleadmaintainer@example.com', - 'active' => 'no', - ); - } - - if (count($arr['lead']) == 1) { - $arr['lead'] = $arr['lead'][0]; - } - - foreach ($maintainers as $maintainer) { - if ($maintainer['role'] == 'lead') { - continue; - } - $new = array( - 'name' => $maintainer['name'], - 'user' => $maintainer['handle'], - 'email' => $maintainer['email'], - 'active' => 'yes', - ); - $arr[$maintainer['role']][] = $new; - } - - if (isset($arr['developer']) && count($arr['developer']) == 1) { - $arr['developer'] = $arr['developer'][0]; - } - - if (isset($arr['contributor']) && count($arr['contributor']) == 1) { - $arr['contributor'] = $arr['contributor'][0]; - } - - if (isset($arr['helper']) && count($arr['helper']) == 1) { - $arr['helper'] = $arr['helper'][0]; - } - - $arr['date'] = $this->_packagefile->getDate(); - $arr['version'] = - array( - 'release' => $this->_packagefile->getVersion(), - 'api' => $this->_packagefile->getVersion(), - ); - $arr['stability'] = - array( - 'release' => $this->_packagefile->getState(), - 'api' => $this->_packagefile->getState(), - ); - $licensemap = - array( - 'php' => 'http://www.php.net/license', - 'php license' => 'http://www.php.net/license', - 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html', - 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php', - 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php', - 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php', - 'mit' => 'http://www.opensource.org/licenses/mit-license.php', - 'gpl' => 'http://www.gnu.org/copyleft/gpl.html', - 'apache' => 'http://www.opensource.org/licenses/apache2.0.php' - ); - - if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) { - $arr['license'] = array( - 'attribs' => array('uri' => - $licensemap[strtolower($this->_packagefile->getLicense())]), - '_content' => $this->_packagefile->getLicense() - ); - } else { - // don't use bogus uri - $arr['license'] = $this->_packagefile->getLicense(); - } - - $arr['notes'] = $this->_packagefile->getNotes(); - $temp = array(); - $arr['contents'] = $this->_convertFilelist2_0($temp); - $this->_convertDependencies2_0($arr); - $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ? - 'extsrcrelease' : 'phprelease'; - if ($release == 'extsrcrelease') { - $arr['channel'] = 'pecl.php.net'; - $arr['providesextension'] = $arr['name']; // assumption - } - - $arr[$release] = array(); - if ($this->_packagefile->getConfigureOptions()) { - $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions(); - foreach ($arr[$release]['configureoption'] as $i => $opt) { - $arr[$release]['configureoption'][$i] = array('attribs' => $opt); - } - if (count($arr[$release]['configureoption']) == 1) { - $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0]; - } - } - - $this->_convertRelease2_0($arr[$release], $temp); - if ($release == 'extsrcrelease' && count($arr[$release]) > 1) { - // multiple extsrcrelease tags added in PEAR 1.4.1 - $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1'; - } - - if ($cl = $this->_packagefile->getChangelog()) { - foreach ($cl as $release) { - $rel = array(); - $rel['version'] = - array( - 'release' => $release['version'], - 'api' => $release['version'], - ); - if (!isset($release['release_state'])) { - $release['release_state'] = 'stable'; - } - - $rel['stability'] = - array( - 'release' => $release['release_state'], - 'api' => $release['release_state'], - ); - if (isset($release['release_date'])) { - $rel['date'] = $release['release_date']; - } else { - $rel['date'] = date('Y-m-d'); - } - - if (isset($release['release_license'])) { - if (isset($licensemap[strtolower($release['release_license'])])) { - $uri = $licensemap[strtolower($release['release_license'])]; - } else { - $uri = 'http://www.example.com'; - } - $rel['license'] = array( - 'attribs' => array('uri' => $uri), - '_content' => $release['release_license'] - ); - } else { - $rel['license'] = $arr['license']; - } - - if (!isset($release['release_notes'])) { - $release['release_notes'] = 'no release notes'; - } - - $rel['notes'] = $release['release_notes']; - $arr['changelog']['release'][] = $rel; - } - } - - $ret = new $class; - $ret->setConfig($this->_packagefile->_config); - if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) { - $ret->setLogger($this->_packagefile->_logger); - } - - $ret->fromArray($arr); - return $ret; - } - - /** - * @param array - * @param bool - * @access private - */ - function _convertDependencies2_0(&$release, $internal = false) - { - $peardep = array('pearinstaller' => - array('min' => '1.4.0b1')); // this is a lot safer - $required = $optional = array(); - $release['dependencies'] = array('required' => array()); - if ($this->_packagefile->hasDeps()) { - foreach ($this->_packagefile->getDeps() as $dep) { - if (!isset($dep['optional']) || $dep['optional'] == 'no') { - $required[] = $dep; - } else { - $optional[] = $dep; - } - } - foreach (array('required', 'optional') as $arr) { - $deps = array(); - foreach ($$arr as $dep) { - // organize deps by dependency type and name - if (!isset($deps[$dep['type']])) { - $deps[$dep['type']] = array(); - } - if (isset($dep['name'])) { - $deps[$dep['type']][$dep['name']][] = $dep; - } else { - $deps[$dep['type']][] = $dep; - } - } - do { - if (isset($deps['php'])) { - $php = array(); - if (count($deps['php']) > 1) { - $php = $this->_processPhpDeps($deps['php']); - } else { - if (!isset($deps['php'][0])) { - list($key, $blah) = each ($deps['php']); // stupid buggy versions - $deps['php'] = array($blah[0]); - } - $php = $this->_processDep($deps['php'][0]); - if (!$php) { - break; // poor mans throw - } - } - $release['dependencies'][$arr]['php'] = $php; - } - } while (false); - do { - if (isset($deps['pkg'])) { - $pkg = array(); - $pkg = $this->_processMultipleDepsName($deps['pkg']); - if (!$pkg) { - break; // poor mans throw - } - $release['dependencies'][$arr]['package'] = $pkg; - } - } while (false); - do { - if (isset($deps['ext'])) { - $pkg = array(); - $pkg = $this->_processMultipleDepsName($deps['ext']); - $release['dependencies'][$arr]['extension'] = $pkg; - } - } while (false); - // skip sapi - it's not supported so nobody will have used it - // skip os - it's not supported in 1.0 - } - } - if (isset($release['dependencies']['required'])) { - $release['dependencies']['required'] = - array_merge($peardep, $release['dependencies']['required']); - } else { - $release['dependencies']['required'] = $peardep; - } - if (!isset($release['dependencies']['required']['php'])) { - $release['dependencies']['required']['php'] = - array('min' => '4.0.0'); - } - $order = array(); - $bewm = $release['dependencies']['required']; - $order['php'] = $bewm['php']; - $order['pearinstaller'] = $bewm['pearinstaller']; - isset($bewm['package']) ? $order['package'] = $bewm['package'] :0; - isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0; - $release['dependencies']['required'] = $order; - } - - /** - * @param array - * @access private - */ - function _convertFilelist2_0(&$package) - { - $ret = array('dir' => - array( - 'attribs' => array('name' => '/'), - 'file' => array() - ) - ); - $package['platform'] = - $package['install-as'] = array(); - $this->_isExtension = false; - foreach ($this->_packagefile->getFilelist() as $name => $file) { - $file['name'] = $name; - if (isset($file['role']) && $file['role'] == 'src') { - $this->_isExtension = true; - } - if (isset($file['replacements'])) { - $repl = $file['replacements']; - unset($file['replacements']); - } else { - unset($repl); - } - if (isset($file['install-as'])) { - $package['install-as'][$name] = $file['install-as']; - unset($file['install-as']); - } - if (isset($file['platform'])) { - $package['platform'][$name] = $file['platform']; - unset($file['platform']); - } - $file = array('attribs' => $file); - if (isset($repl)) { - foreach ($repl as $replace ) { - $file['tasks:replace'][] = array('attribs' => $replace); - } - if (count($repl) == 1) { - $file['tasks:replace'] = $file['tasks:replace'][0]; - } - } - $ret['dir']['file'][] = $file; - } - return $ret; - } - - /** - * Post-process special files with install-as/platform attributes and - * make the release tag. - * - * This complex method follows this work-flow to create the release tags: - * - *
    -     * - if any install-as/platform exist, create a generic release and fill it with
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     * - create a release for each platform encountered and fill with
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     *   o  tags for 
    -     * 
    - * - * It does this by accessing the $package parameter, which contains an array with - * indices: - * - * - platform: mapping of file => OS the file should be installed on - * - install-as: mapping of file => installed name - * - osmap: mapping of OS => list of files that should be installed - * on that OS - * - notosmap: mapping of OS => list of files that should not be - * installed on that OS - * - * @param array - * @param array - * @access private - */ - function _convertRelease2_0(&$release, $package) - { - //- if any install-as/platform exist, create a generic release and fill it with - if (count($package['platform']) || count($package['install-as'])) { - $generic = array(); - $genericIgnore = array(); - foreach ($package['install-as'] as $file => $as) { - //o tags for - if (!isset($package['platform'][$file])) { - $generic[] = $file; - continue; - } - //o tags for - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} == '!') { - $generic[] = $file; - continue; - } - //o tags for - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} != '!') { - $genericIgnore[] = $file; - continue; - } - } - foreach ($package['platform'] as $file => $platform) { - if (isset($package['install-as'][$file])) { - continue; - } - if ($platform{0} != '!') { - //o tags for - $genericIgnore[] = $file; - } - } - if (count($package['platform'])) { - $oses = $notplatform = $platform = array(); - foreach ($package['platform'] as $file => $os) { - // get a list of oses - if ($os{0} == '!') { - if (isset($oses[substr($os, 1)])) { - continue; - } - $oses[substr($os, 1)] = count($oses); - } else { - if (isset($oses[$os])) { - continue; - } - $oses[$os] = count($oses); - } - } - //- create a release for each platform encountered and fill with - foreach ($oses as $os => $releaseNum) { - $release[$releaseNum]['installconditions']['os']['name'] = $os; - $release[$releaseNum]['filelist'] = array('install' => array(), - 'ignore' => array()); - foreach ($package['install-as'] as $file => $as) { - //o tags for - if (!isset($package['platform'][$file])) { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] == $os) { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] != "!$os" && - $package['platform'][$file]{0} == '!') { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] == "!$os") { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} != '!' && - $package['platform'][$file] != $os) { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - } - foreach ($package['platform'] as $file => $platform) { - if (isset($package['install-as'][$file])) { - continue; - } - //o tags for - if ($platform == "!$os") { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - //o tags for - if ($platform{0} != '!' && $platform != $os) { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - } - } - if (!count($release[$releaseNum]['filelist']['install'])) { - unset($release[$releaseNum]['filelist']['install']); - } - if (!count($release[$releaseNum]['filelist']['ignore'])) { - unset($release[$releaseNum]['filelist']['ignore']); - } - } - if (count($generic) || count($genericIgnore)) { - $release[count($oses)] = array(); - if (count($generic)) { - foreach ($generic as $file) { - if (isset($package['install-as'][$file])) { - $installas = $package['install-as'][$file]; - } else { - $installas = $file; - } - $release[count($oses)]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $installas, - ) - ); - } - } - if (count($genericIgnore)) { - foreach ($genericIgnore as $file) { - $release[count($oses)]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ) - ); - } - } - } - // cleanup - foreach ($release as $i => $rel) { - if (isset($rel['filelist']['install']) && - count($rel['filelist']['install']) == 1) { - $release[$i]['filelist']['install'] = - $release[$i]['filelist']['install'][0]; - } - if (isset($rel['filelist']['ignore']) && - count($rel['filelist']['ignore']) == 1) { - $release[$i]['filelist']['ignore'] = - $release[$i]['filelist']['ignore'][0]; - } - } - if (count($release) == 1) { - $release = $release[0]; - } - } else { - // no platform atts, but some install-as atts - foreach ($package['install-as'] as $file => $value) { - $release['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $value - ) - ); - } - if (count($release['filelist']['install']) == 1) { - $release['filelist']['install'] = $release['filelist']['install'][0]; - } - } - } - } - - /** - * @param array - * @return array - * @access private - */ - function _processDep($dep) - { - if ($dep['type'] == 'php') { - if ($dep['rel'] == 'has') { - // come on - everyone has php! - return false; - } - } - $php = array(); - if ($dep['type'] != 'php') { - $php['name'] = $dep['name']; - if ($dep['type'] == 'pkg') { - $php['channel'] = 'pear.php.net'; - } - } - switch ($dep['rel']) { - case 'gt' : - $php['min'] = $dep['version']; - $php['exclude'] = $dep['version']; - break; - case 'ge' : - if (!isset($dep['version'])) { - if ($dep['type'] == 'php') { - if (isset($dep['name'])) { - $dep['version'] = $dep['name']; - } - } - } - $php['min'] = $dep['version']; - break; - case 'lt' : - $php['max'] = $dep['version']; - $php['exclude'] = $dep['version']; - break; - case 'le' : - $php['max'] = $dep['version']; - break; - case 'eq' : - $php['min'] = $dep['version']; - $php['max'] = $dep['version']; - break; - case 'ne' : - $php['exclude'] = $dep['version']; - break; - case 'not' : - $php['conflicts'] = 'yes'; - break; - } - return $php; - } - - /** - * @param array - * @return array - */ - function _processPhpDeps($deps) - { - $test = array(); - foreach ($deps as $dep) { - $test[] = $this->_processDep($dep); - } - $min = array(); - $max = array(); - foreach ($test as $dep) { - if (!$dep) { - continue; - } - if (isset($dep['min'])) { - $min[$dep['min']] = count($min); - } - if (isset($dep['max'])) { - $max[$dep['max']] = count($max); - } - } - if (count($min) > 0) { - uksort($min, 'version_compare'); - } - if (count($max) > 0) { - uksort($max, 'version_compare'); - } - if (count($min)) { - // get the highest minimum - $min = array_pop($a = array_flip($min)); - } else { - $min = false; - } - if (count($max)) { - // get the lowest maximum - $max = array_shift($a = array_flip($max)); - } else { - $max = false; - } - if ($min) { - $php['min'] = $min; - } - if ($max) { - $php['max'] = $max; - } - $exclude = array(); - foreach ($test as $dep) { - if (!isset($dep['exclude'])) { - continue; - } - $exclude[] = $dep['exclude']; - } - if (count($exclude)) { - $php['exclude'] = $exclude; - } - return $php; - } - - /** - * process multiple dependencies that have a name, like package deps - * @param array - * @return array - * @access private - */ - function _processMultipleDepsName($deps) - { - $ret = $tests = array(); - foreach ($deps as $name => $dep) { - foreach ($dep as $d) { - $tests[$name][] = $this->_processDep($d); - } - } - - foreach ($tests as $name => $test) { - $max = $min = $php = array(); - $php['name'] = $name; - foreach ($test as $dep) { - if (!$dep) { - continue; - } - if (isset($dep['channel'])) { - $php['channel'] = 'pear.php.net'; - } - if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') { - $php['conflicts'] = 'yes'; - } - if (isset($dep['min'])) { - $min[$dep['min']] = count($min); - } - if (isset($dep['max'])) { - $max[$dep['max']] = count($max); - } - } - if (count($min) > 0) { - uksort($min, 'version_compare'); - } - if (count($max) > 0) { - uksort($max, 'version_compare'); - } - if (count($min)) { - // get the highest minimum - $min = array_pop($a = array_flip($min)); - } else { - $min = false; - } - if (count($max)) { - // get the lowest maximum - $max = array_shift($a = array_flip($max)); - } else { - $max = false; - } - if ($min) { - $php['min'] = $min; - } - if ($max) { - $php['max'] = $max; - } - $exclude = array(); - foreach ($test as $dep) { - if (!isset($dep['exclude'])) { - continue; - } - $exclude[] = $dep['exclude']; - } - if (count($exclude)) { - $php['exclude'] = $exclude; - } - $ret[] = $php; - } - return $ret; - } -} -?> - * @author Stephan Schmidt (original XML_Serializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php 278907 2009-04-17 21:10:04Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * file/dir manipulation routines - */ -require_once 'phar://go-pear.phar/' . 'System.php'; -require_once 'phar://go-pear.phar/' . 'XML/Util.php'; - -/** - * This class converts a PEAR_PackageFile_v2 object into any output format. - * - * Supported output formats include array, XML string (using S. Schmidt's - * XML_Serializer, slightly customized) - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stephan Schmidt (original XML_Serializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Generator_v2 -{ - /** - * default options for the serialization - * @access private - * @var array $_defaultOptions - */ - var $_defaultOptions = array( - 'indent' => ' ', // string used for indentation - 'linebreak' => "\n", // string used for newlines - 'typeHints' => false, // automatically add type hin attributes - 'addDecl' => true, // add an XML declaration - 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names - 'classAsTagName' => false, // use classname for objects in indexed arrays - 'keyAttribute' => '_originalKey', // attribute where original key is stored - 'typeAttribute' => '_type', // attribute for type (only if typeHints => true) - 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true) - 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute - 'prependAttributes' => '', // prepend string for attributes - 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column - 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array - 'addDoctype' => false, // add a doctype declaration - 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()} - 'rootName' => 'package', // name of the root tag - 'rootAttributes' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 -http://pear.php.net/dtd/tasks-1.0.xsd -http://pear.php.net/dtd/package-2.0 -http://pear.php.net/dtd/package-2.0.xsd', - ), // attributes of the root tag - 'attributesArray' => 'attribs', // all values in this key will be treated as attributes - 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray - 'beautifyFilelist' => false, - 'encoding' => 'UTF-8', - ); - - /** - * options for the serialization - * @access private - * @var array $options - */ - var $options = array(); - - /** - * current tag depth - * @var integer $_tagDepth - */ - var $_tagDepth = 0; - - /** - * serilialized representation of the data - * @var string $_serializedData - */ - var $_serializedData = null; - /** - * @var PEAR_PackageFile_v2 - */ - var $_packagefile; - /** - * @param PEAR_PackageFile_v2 - */ - function PEAR_PackageFile_Generator_v2(&$packagefile) - { - $this->_packagefile = &$packagefile; - if (isset($this->_packagefile->encoding)) { - $this->_defaultOptions['encoding'] = $this->_packagefile->encoding; - } - } - - /** - * @return string - */ - function getPackagerVersion() - { - return '1.9.0'; - } - - /** - * @param PEAR_Packager - * @param bool generate a .tgz or a .tar - * @param string|null temporary directory to package in - */ - function toTgz(&$packager, $compress = true, $where = null) - { - $a = null; - return $this->toTgz2($packager, $a, $compress, $where); - } - - /** - * Package up both a package.xml and package2.xml for the same release - * @param PEAR_Packager - * @param PEAR_PackageFile_v1 - * @param bool generate a .tgz or a .tar - * @param string|null temporary directory to package in - */ - function toTgz2(&$packager, &$pf1, $compress = true, $where = null) - { - require_once 'phar://go-pear.phar/' . 'Archive/Tar.php'; - if (!$this->_packagefile->isEquivalent($pf1)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . - basename($pf1->getPackageFile()) . - '" is not equivalent to "' . basename($this->_packagefile->getPackageFile()) - . '"'); - } - - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' . - ' not be created'); - } - - $file = $where . DIRECTORY_SEPARATOR . 'package.xml'; - if (file_exists($file) && !is_file($file)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' . - ' "' . $file .'"'); - } - - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml'); - } - - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion(); - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; - if (file_exists($dest_package) && !is_file($dest_package)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' . - $dest_package . '"'); - } - - $pkgfile = $this->_packagefile->getPackageFile(); - if (!$pkgfile) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' . - 'be created from a real file'); - } - - $pkgdir = dirname(realpath($pkgfile)); - $pkgfile = basename($pkgfile); - - // {{{ Create the package file list - $filelist = array(); - $i = 0; - $this->_packagefile->flattenFilelist(); - $contents = $this->_packagefile->getContents(); - if (isset($contents['bundledpackage'])) { // bundles of packages - $contents = $contents['bundledpackage']; - if (!isset($contents[0])) { - $contents = array($contents); - } - - $packageDir = $where; - foreach ($contents as $i => $package) { - $fname = $package; - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return $packager->raiseError("File does not exist: $fname"); - } - - $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; - System::mkdir(array('-p', dirname($tfile))); - copy($file, $tfile); - $filelist[$i++] = $tfile; - $packager->log(2, "Adding package $fname"); - } - } else { // normal packages - $contents = $contents['dir']['file']; - if (!isset($contents[0])) { - $contents = array($contents); - } - - $packageDir = $where; - foreach ($contents as $i => $file) { - $fname = $file['attribs']['name']; - $atts = $file['attribs']; - $orig = $file; - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return $packager->raiseError("File does not exist: $fname"); - } - - $origperms = fileperms($file); - $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; - unset($orig['attribs']); - if (count($orig)) { // file with tasks - // run any package-time tasks - $contents = file_get_contents($file); - foreach ($orig as $tag => $raw) { - $tag = str_replace( - array($this->_packagefile->getTasksNs() . ':', '-'), - array('', '_'), $tag); - $task = "PEAR_Task_$tag"; - $task = &new $task($this->_packagefile->_config, - $this->_packagefile->_logger, - PEAR_TASK_PACKAGE); - $task->init($raw, $atts, null); - $res = $task->startSession($this->_packagefile, $contents, $tfile); - if (!$res) { - continue; // skip this task - } - - if (PEAR::isError($res)) { - return $res; - } - - $contents = $res; // save changes - System::mkdir(array('-p', dirname($tfile))); - $wp = fopen($tfile, "wb"); - fwrite($wp, $contents); - fclose($wp); - } - } - - if (!file_exists($tfile)) { - System::mkdir(array('-p', dirname($tfile))); - copy($file, $tfile); - } - - chmod($tfile, $origperms); - $filelist[$i++] = $tfile; - $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1); - $packager->log(2, "Adding file $fname"); - } - } - // }}} - - $name = $pf1 !== null ? 'package2.xml' : 'package.xml'; - $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name); - if ($packagexml) { - $tar =& new Archive_Tar($dest_package, $compress); - $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors - // ----- Creates with the package.xml file - $ok = $tar->createModify(array($packagexml), '', $where); - if (PEAR::isError($ok)) { - return $packager->raiseError($ok); - } elseif (!$ok) { - return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name . - ' failed'); - } - - // ----- Add the content of the package - if (!$tar->addModify($filelist, $pkgver, $where)) { - return $packager->raiseError( - 'PEAR_Packagefile_v2::toTgz(): tarball creation failed'); - } - - // add the package.xml version 1.0 - if ($pf1 !== null) { - $pfgen = &$pf1->getDefaultGenerator(); - $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); - if (!$tar->addModify(array($packagexml1), '', $where)) { - return $packager->raiseError( - 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed'); - } - } - - return $dest_package; - } - } - - function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml') - { - if (!$this->_packagefile->validate($state)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml', - null, null, null, $this->_packagefile->getValidationWarnings()); - } - - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' . - ' not be created'); - } - - $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; - $np = @fopen($newpkgfile, 'wb'); - if (!$np) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' . - "$name as $newpkgfile"); - } - fwrite($np, $this->toXml($state)); - fclose($np); - return $newpkgfile; - } - - function &toV2() - { - return $this->_packagefile; - } - - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @return string XML data - */ - function toXml($state = PEAR_VALIDATE_NORMAL, $options = array()) - { - $this->_packagefile->setDate(date('Y-m-d')); - $this->_packagefile->setTime(date('H:i:s')); - if (!$this->_packagefile->validate($state)) { - return false; - } - - if (is_array($options)) { - $this->options = array_merge($this->_defaultOptions, $options); - } else { - $this->options = $this->_defaultOptions; - } - - $arr = $this->_packagefile->getArray(); - if (isset($arr['filelist'])) { - unset($arr['filelist']); - } - - if (isset($arr['_lastversion'])) { - unset($arr['_lastversion']); - } - - // Fix the notes a little bit - if (isset($arr['notes'])) { - // This trims out the indenting, needs fixing - $arr['notes'] = "\n" . trim($arr['notes']) . "\n"; - } - - if (isset($arr['changelog']) && !empty($arr['changelog'])) { - // Fix for inconsistency how the array is filled depending on the changelog release amount - if (!isset($arr['changelog']['release'][0])) { - $release = $arr['changelog']['release']; - unset($arr['changelog']['release']); - - $arr['changelog']['release'] = array(); - $arr['changelog']['release'][0] = $release; - } - - foreach (array_keys($arr['changelog']['release']) as $key) { - $c =& $arr['changelog']['release'][$key]; - if (isset($c['notes'])) { - // This trims out the indenting, needs fixing - $c['notes'] = "\n" . trim($c['notes']) . "\n"; - } - } - } - - if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) { - $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']); - unset($arr['contents']['dir']['file']); - if (isset($use['dir'])) { - $arr['contents']['dir']['dir'] = $use['dir']; - } - if (isset($use['file'])) { - $arr['contents']['dir']['file'] = $use['file']; - } - $this->options['beautifyFilelist'] = true; - } - - $arr['attribs']['packagerversion'] = '1.9.0'; - if ($this->serialize($arr, $options)) { - return $this->_serializedData . "\n"; - } - - return false; - } - - - function _recursiveXmlFilelist($list) - { - $dirs = array(); - if (isset($list['attribs'])) { - $file = $list['attribs']['name']; - unset($list['attribs']['name']); - $attributes = $list['attribs']; - $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes); - } else { - foreach ($list as $a) { - $file = $a['attribs']['name']; - $attributes = $a['attribs']; - unset($a['attribs']); - $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a); - } - } - $this->_formatDir($dirs); - $this->_deFormat($dirs); - return $dirs; - } - - function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null) - { - if (!$tasks) { - $tasks = array(); - } - if ($dir == array() || $dir == array('.')) { - $dirs['file'][basename($file)] = $tasks; - $attributes['name'] = basename($file); - $dirs['file'][basename($file)]['attribs'] = $attributes; - return; - } - $curdir = array_shift($dir); - if (!isset($dirs['dir'][$curdir])) { - $dirs['dir'][$curdir] = array(); - } - $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks); - } - - function _formatDir(&$dirs) - { - if (!count($dirs)) { - return array(); - } - $newdirs = array(); - if (isset($dirs['dir'])) { - $newdirs['dir'] = $dirs['dir']; - } - if (isset($dirs['file'])) { - $newdirs['file'] = $dirs['file']; - } - $dirs = $newdirs; - if (isset($dirs['dir'])) { - uksort($dirs['dir'], 'strnatcasecmp'); - foreach ($dirs['dir'] as $dir => $contents) { - $this->_formatDir($dirs['dir'][$dir]); - } - } - if (isset($dirs['file'])) { - uksort($dirs['file'], 'strnatcasecmp'); - }; - } - - function _deFormat(&$dirs) - { - if (!count($dirs)) { - return array(); - } - $newdirs = array(); - if (isset($dirs['dir'])) { - foreach ($dirs['dir'] as $dir => $contents) { - $newdir = array(); - $newdir['attribs']['name'] = $dir; - $this->_deFormat($contents); - foreach ($contents as $tag => $val) { - $newdir[$tag] = $val; - } - $newdirs['dir'][] = $newdir; - } - if (count($newdirs['dir']) == 1) { - $newdirs['dir'] = $newdirs['dir'][0]; - } - } - if (isset($dirs['file'])) { - foreach ($dirs['file'] as $name => $file) { - $newdirs['file'][] = $file; - } - if (count($newdirs['file']) == 1) { - $newdirs['file'] = $newdirs['file'][0]; - } - } - $dirs = $newdirs; - } - - /** - * reset all options to default options - * - * @access public - * @see setOption(), XML_Unserializer() - */ - function resetOptions() - { - $this->options = $this->_defaultOptions; - } - - /** - * set an option - * - * You can use this method if you do not want to set all options in the constructor - * - * @access public - * @see resetOption(), XML_Serializer() - */ - function setOption($name, $value) - { - $this->options[$name] = $value; - } - - /** - * sets several options at once - * - * You can use this method if you do not want to set all options in the constructor - * - * @access public - * @see resetOption(), XML_Unserializer(), setOption() - */ - function setOptions($options) - { - $this->options = array_merge($this->options, $options); - } - - /** - * serialize data - * - * @access public - * @param mixed $data data to serialize - * @return boolean true on success, pear error on failure - */ - function serialize($data, $options = null) - { - // if options have been specified, use them instead - // of the previously defined ones - if (is_array($options)) { - $optionsBak = $this->options; - if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) { - $this->options = array_merge($this->_defaultOptions, $options); - } else { - $this->options = array_merge($this->options, $options); - } - } else { - $optionsBak = null; - } - - // start depth is zero - $this->_tagDepth = 0; - $this->_serializedData = ''; - // serialize an array - if (is_array($data)) { - $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array'; - $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']); - } - - // add doctype declaration - if ($this->options['addDoctype'] === true) { - $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype']) - . $this->options['linebreak'] - . $this->_serializedData; - } - - // build xml declaration - if ($this->options['addDecl']) { - $atts = array(); - $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null; - $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding) - . $this->options['linebreak'] - . $this->_serializedData; - } - - - if ($optionsBak !== null) { - $this->options = $optionsBak; - } - - return true; - } - - /** - * get the result of the serialization - * - * @access public - * @return string serialized XML - */ - function getSerializedData() - { - if ($this->_serializedData === null) { - return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION); - } - return $this->_serializedData; - } - - /** - * serialize any value - * - * This method checks for the type of the value and calls the appropriate method - * - * @access private - * @param mixed $value - * @param string $tagName - * @param array $attributes - * @return string - */ - function _serializeValue($value, $tagName = null, $attributes = array()) - { - if (is_array($value)) { - $xml = $this->_serializeArray($value, $tagName, $attributes); - } elseif (is_object($value)) { - $xml = $this->_serializeObject($value, $tagName); - } else { - $tag = array( - 'qname' => $tagName, - 'attributes' => $attributes, - 'content' => $value - ); - $xml = $this->_createXMLTag($tag); - } - return $xml; - } - - /** - * serialize an array - * - * @access private - * @param array $array array to serialize - * @param string $tagName name of the root tag - * @param array $attributes attributes for the root tag - * @return string $string serialized data - * @uses XML_Util::isValidName() to check, whether key has to be substituted - */ - function _serializeArray(&$array, $tagName = null, $attributes = array()) - { - $_content = null; - - /** - * check for special attributes - */ - if ($this->options['attributesArray'] !== null) { - if (isset($array[$this->options['attributesArray']])) { - $attributes = $array[$this->options['attributesArray']]; - unset($array[$this->options['attributesArray']]); - } - /** - * check for special content - */ - if ($this->options['contentName'] !== null) { - if (isset($array[$this->options['contentName']])) { - $_content = $array[$this->options['contentName']]; - unset($array[$this->options['contentName']]); - } - } - } - - /* - * if mode is set to simpleXML, check whether - * the array is associative or indexed - */ - if (is_array($array) && $this->options['mode'] == 'simplexml') { - $indexed = true; - if (!count($array)) { - $indexed = false; - } - foreach ($array as $key => $val) { - if (!is_int($key)) { - $indexed = false; - break; - } - } - - if ($indexed && $this->options['mode'] == 'simplexml') { - $string = ''; - foreach ($array as $key => $val) { - if ($this->options['beautifyFilelist'] && $tagName == 'dir') { - if (!isset($this->_curdir)) { - $this->_curdir = ''; - } - $savedir = $this->_curdir; - if (isset($val['attribs'])) { - if ($val['attribs']['name'] == '/') { - $this->_curdir = '/'; - } else { - if ($this->_curdir == '/') { - $this->_curdir = ''; - } - $this->_curdir .= '/' . $val['attribs']['name']; - } - } - } - $string .= $this->_serializeValue( $val, $tagName, $attributes); - if ($this->options['beautifyFilelist'] && $tagName == 'dir') { - $string .= ' '; - if (empty($savedir)) { - unset($this->_curdir); - } else { - $this->_curdir = $savedir; - } - } - - $string .= $this->options['linebreak']; - // do indentation - if ($this->options['indent'] !== null && $this->_tagDepth > 0) { - $string .= str_repeat($this->options['indent'], $this->_tagDepth); - } - } - return rtrim($string); - } - } - - if ($this->options['scalarAsAttributes'] === true) { - foreach ($array as $key => $value) { - if (is_scalar($value) && (XML_Util::isValidName($key) === true)) { - unset($array[$key]); - $attributes[$this->options['prependAttributes'].$key] = $value; - } - } - } - - // check for empty array => create empty tag - if (empty($array)) { - $tag = array( - 'qname' => $tagName, - 'content' => $_content, - 'attributes' => $attributes - ); - - } else { - $this->_tagDepth++; - $tmp = $this->options['linebreak']; - foreach ($array as $key => $value) { - // do indentation - if ($this->options['indent'] !== null && $this->_tagDepth > 0) { - $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); - } - - // copy key - $origKey = $key; - // key cannot be used as tagname => use default tag - $valid = XML_Util::isValidName($key); - if (PEAR::isError($valid)) { - if ($this->options['classAsTagName'] && is_object($value)) { - $key = get_class($value); - } else { - $key = $this->options['defaultTagName']; - } - } - $atts = array(); - if ($this->options['typeHints'] === true) { - $atts[$this->options['typeAttribute']] = gettype($value); - if ($key !== $origKey) { - $atts[$this->options['keyAttribute']] = (string)$origKey; - } - - } - if ($this->options['beautifyFilelist'] && $key == 'dir') { - if (!isset($this->_curdir)) { - $this->_curdir = ''; - } - $savedir = $this->_curdir; - if (isset($value['attribs'])) { - if ($value['attribs']['name'] == '/') { - $this->_curdir = '/'; - } else { - $this->_curdir .= '/' . $value['attribs']['name']; - } - } - } - - if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) { - $value .= str_repeat($this->options['indent'], $this->_tagDepth); - } - $tmp .= $this->_createXMLTag(array( - 'qname' => $key, - 'attributes' => $atts, - 'content' => $value ) - ); - if ($this->options['beautifyFilelist'] && $key == 'dir') { - if (isset($value['attribs'])) { - $tmp .= ' '; - if (empty($savedir)) { - unset($this->_curdir); - } else { - $this->_curdir = $savedir; - } - } - } - $tmp .= $this->options['linebreak']; - } - - $this->_tagDepth--; - if ($this->options['indent']!==null && $this->_tagDepth>0) { - $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); - } - - if (trim($tmp) === '') { - $tmp = null; - } - - $tag = array( - 'qname' => $tagName, - 'content' => $tmp, - 'attributes' => $attributes - ); - } - if ($this->options['typeHints'] === true) { - if (!isset($tag['attributes'][$this->options['typeAttribute']])) { - $tag['attributes'][$this->options['typeAttribute']] = 'array'; - } - } - - $string = $this->_createXMLTag($tag, false); - return $string; - } - - /** - * create a tag from an array - * this method awaits an array in the following format - * array( - * 'qname' => $tagName, - * 'attributes' => array(), - * 'content' => $content, // optional - * 'namespace' => $namespace // optional - * 'namespaceUri' => $namespaceUri // optional - * ) - * - * @access private - * @param array $tag tag definition - * @param boolean $replaceEntities whether to replace XML entities in content or not - * @return string $string XML tag - */ - function _createXMLTag($tag, $replaceEntities = true) - { - if ($this->options['indentAttributes'] !== false) { - $multiline = true; - $indent = str_repeat($this->options['indent'], $this->_tagDepth); - - if ($this->options['indentAttributes'] == '_auto') { - $indent .= str_repeat(' ', (strlen($tag['qname'])+2)); - - } else { - $indent .= $this->options['indentAttributes']; - } - } else { - $indent = $multiline = false; - } - - if (is_array($tag['content'])) { - if (empty($tag['content'])) { - $tag['content'] = ''; - } - } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') { - $tag['content'] = ''; - } - - if (is_scalar($tag['content']) || is_null($tag['content'])) { - if ($this->options['encoding'] == 'UTF-8' && - version_compare(phpversion(), '5.0.0', 'lt') - ) { - $tag['content'] = utf8_encode($tag['content']); - } - - if ($replaceEntities === true) { - $replaceEntities = XML_UTIL_ENTITIES_XML; - } - - $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']); - } elseif (is_array($tag['content'])) { - $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']); - } elseif (is_object($tag['content'])) { - $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']); - } elseif (is_resource($tag['content'])) { - settype($tag['content'], 'string'); - $tag = XML_Util::createTagFromArray($tag, $replaceEntities); - } - return $tag; - } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * package.xml abstraction class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php'; -/** - * Parser for package.xml version 1.0 - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Parser_v1 -{ - var $_registry; - var $_config; - var $_logger; - /** - * BC hack to allow PEAR_Common::infoFromString() to sort of - * work with the version 2.0 format - there's no filelist though - * @param PEAR_PackageFile_v2 - */ - function fromV2($packagefile) - { - $info = $packagefile->getArray(true); - $ret = new PEAR_PackageFile_v1; - $ret->fromArray($info['old']); - } - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - /** - * @param string contents of package.xml file, version 1.0 - * @return bool success of parsing - */ - function &parse($data, $file, $archive = false) - { - if (!extension_loaded('xml')) { - return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension'); - } - $xp = xml_parser_create(); - if (!$xp) { - $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml'); - return $a; - } - xml_set_object($xp, $this); - xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0'); - xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0'); - xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); - - $this->element_stack = array(); - $this->_packageInfo = array('provides' => array()); - $this->current_element = false; - unset($this->dir_install); - $this->_packageInfo['filelist'] = array(); - $this->filelist =& $this->_packageInfo['filelist']; - $this->dir_names = array(); - $this->in_changelog = false; - $this->d_i = 0; - $this->cdata = ''; - $this->_isValid = true; - - if (!xml_parse($xp, $data, 1)) { - $code = xml_get_error_code($xp); - $line = xml_get_current_line_number($xp); - xml_parser_free($xp); - $a = &PEAR::raiseError(sprintf("XML error: %s at line %d", - $str = xml_error_string($code), $line), 2); - return $a; - } - - xml_parser_free($xp); - - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - if (isset($this->_logger)) { - $pf->setLogger($this->_logger); - } - $pf->setPackagefile($file, $archive); - $pf->fromArray($this->_packageInfo); - return $pf; - } - // {{{ _unIndent() - - /** - * Unindent given string - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } elseif (trim(substr($line, 0, $indent_len))) { - $data .= ltrim($line); - } - } - return $data; - } - - // Support for package DTD v1.0: - // {{{ _element_start_1_0() - - /** - * XML parser callback for ending elements. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name name of ending element - * - * @return void - * - * @access private - */ - function _element_start_1_0($xp, $name, $attribs) - { - array_push($this->element_stack, $name); - $this->current_element = $name; - $spos = sizeof($this->element_stack) - 2; - $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; - $this->current_attributes = $attribs; - $this->cdata = ''; - switch ($name) { - case 'dir': - if ($this->in_changelog) { - break; - } - if (array_key_exists('name', $attribs) && $attribs['name'] != '/') { - $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attribs['name']); - if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) { - $attribs['name'] = substr($attribs['name'], 0, - strlen($attribs['name']) - 1); - } - if (strpos($attribs['name'], '/') === 0) { - $attribs['name'] = substr($attribs['name'], 1); - } - $this->dir_names[] = $attribs['name']; - } - if (isset($attribs['baseinstalldir'])) { - $this->dir_install = $attribs['baseinstalldir']; - } - if (isset($attribs['role'])) { - $this->dir_role = $attribs['role']; - } - break; - case 'file': - if ($this->in_changelog) { - break; - } - if (isset($attribs['name'])) { - $path = ''; - if (count($this->dir_names)) { - foreach ($this->dir_names as $dir) { - $path .= $dir . '/'; - } - } - $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attribs['name']); - unset($attribs['name']); - $this->current_path = $path; - $this->filelist[$path] = $attribs; - // Set the baseinstalldir only if the file don't have this attrib - if (!isset($this->filelist[$path]['baseinstalldir']) && - isset($this->dir_install)) - { - $this->filelist[$path]['baseinstalldir'] = $this->dir_install; - } - // Set the Role - if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { - $this->filelist[$path]['role'] = $this->dir_role; - } - } - break; - case 'replace': - if (!$this->in_changelog) { - $this->filelist[$this->current_path]['replacements'][] = $attribs; - } - break; - case 'maintainers': - $this->_packageInfo['maintainers'] = array(); - $this->m_i = 0; // maintainers array index - break; - case 'maintainer': - // compatibility check - if (!isset($this->_packageInfo['maintainers'])) { - $this->_packageInfo['maintainers'] = array(); - $this->m_i = 0; - } - $this->_packageInfo['maintainers'][$this->m_i] = array(); - $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i]; - break; - case 'changelog': - $this->_packageInfo['changelog'] = array(); - $this->c_i = 0; // changelog array index - $this->in_changelog = true; - break; - case 'release': - if ($this->in_changelog) { - $this->_packageInfo['changelog'][$this->c_i] = array(); - $this->current_release = &$this->_packageInfo['changelog'][$this->c_i]; - } else { - $this->current_release = &$this->_packageInfo; - } - break; - case 'deps': - if (!$this->in_changelog) { - $this->_packageInfo['release_deps'] = array(); - } - break; - case 'dep': - // dependencies array index - if (!$this->in_changelog) { - $this->d_i++; - isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false; - $this->_packageInfo['release_deps'][$this->d_i] = $attribs; - } - break; - case 'configureoptions': - if (!$this->in_changelog) { - $this->_packageInfo['configure_options'] = array(); - } - break; - case 'configureoption': - if (!$this->in_changelog) { - $this->_packageInfo['configure_options'][] = $attribs; - } - break; - case 'provides': - if (empty($attribs['type']) || empty($attribs['name'])) { - break; - } - $attribs['explicit'] = true; - $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs; - break; - case 'package' : - if (isset($attribs['version'])) { - $this->_packageInfo['xsdversion'] = trim($attribs['version']); - } else { - $this->_packageInfo['xsdversion'] = '1.0'; - } - if (isset($attribs['packagerversion'])) { - $this->_packageInfo['packagerversion'] = $attribs['packagerversion']; - } - break; - } - } - - // }}} - // {{{ _element_end_1_0() - - /** - * XML parser callback for ending elements. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name name of ending element - * - * @return void - * - * @access private - */ - function _element_end_1_0($xp, $name) - { - $data = trim($this->cdata); - switch ($name) { - case 'name': - switch ($this->prev_element) { - case 'package': - $this->_packageInfo['package'] = $data; - break; - case 'maintainer': - $this->current_maintainer['name'] = $data; - break; - } - break; - case 'extends' : - $this->_packageInfo['extends'] = $data; - break; - case 'summary': - $this->_packageInfo['summary'] = $data; - break; - case 'description': - $data = $this->_unIndent($this->cdata); - $this->_packageInfo['description'] = $data; - break; - case 'user': - $this->current_maintainer['handle'] = $data; - break; - case 'email': - $this->current_maintainer['email'] = $data; - break; - case 'role': - $this->current_maintainer['role'] = $data; - break; - case 'version': - if ($this->in_changelog) { - $this->current_release['version'] = $data; - } else { - $this->_packageInfo['version'] = $data; - } - break; - case 'date': - if ($this->in_changelog) { - $this->current_release['release_date'] = $data; - } else { - $this->_packageInfo['release_date'] = $data; - } - break; - case 'notes': - // try to "de-indent" release notes in case someone - // has been over-indenting their xml ;-) - // Trim only on the right side - $data = rtrim($this->_unIndent($this->cdata)); - if ($this->in_changelog) { - $this->current_release['release_notes'] = $data; - } else { - $this->_packageInfo['release_notes'] = $data; - } - break; - case 'warnings': - if ($this->in_changelog) { - $this->current_release['release_warnings'] = $data; - } else { - $this->_packageInfo['release_warnings'] = $data; - } - break; - case 'state': - if ($this->in_changelog) { - $this->current_release['release_state'] = $data; - } else { - $this->_packageInfo['release_state'] = $data; - } - break; - case 'license': - if ($this->in_changelog) { - $this->current_release['release_license'] = $data; - } else { - $this->_packageInfo['release_license'] = $data; - } - break; - case 'dep': - if ($data && !$this->in_changelog) { - $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data; - } - break; - case 'dir': - if ($this->in_changelog) { - break; - } - array_pop($this->dir_names); - break; - case 'file': - if ($this->in_changelog) { - break; - } - if ($data) { - $path = ''; - if (count($this->dir_names)) { - foreach ($this->dir_names as $dir) { - $path .= $dir . '/'; - } - } - $path .= $data; - $this->filelist[$path] = $this->current_attributes; - // Set the baseinstalldir only if the file don't have this attrib - if (!isset($this->filelist[$path]['baseinstalldir']) && - isset($this->dir_install)) - { - $this->filelist[$path]['baseinstalldir'] = $this->dir_install; - } - // Set the Role - if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { - $this->filelist[$path]['role'] = $this->dir_role; - } - } - break; - case 'maintainer': - if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) { - $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead'; - } - $this->m_i++; - break; - case 'release': - if ($this->in_changelog) { - $this->c_i++; - } - break; - case 'changelog': - $this->in_changelog = false; - break; - } - array_pop($this->element_stack); - $spos = sizeof($this->element_stack) - 1; - $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : ''; - $this->cdata = ''; - } - - // }}} - // {{{ _pkginfo_cdata_1_0() - - /** - * XML parser callback for character data. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name character data - * - * @return void - * - * @access private - */ - function _pkginfo_cdata_1_0($xp, $data) - { - if (isset($this->cdata)) { - $this->cdata .= $data; - } - } - - // }}} -} -?> - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * base xml parser class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; -/** - * Parser for package.xml version 2.0 - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser -{ - var $_config; - var $_logger; - var $_registry; - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - /** - * Unindent given string - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } else { - $data .= $line . "\n"; - } - } - return $data; - } - - /** - * post-process data - * - * @param string $data - * @param string $element element name - */ - function postProcess($data, $element) - { - if ($element == 'notes') { - return trim($this->_unIndent($data)); - } - return trim($data); - } - - /** - * @param string - * @param string file name of the package.xml - * @param string|false name of the archive this package.xml came from, if any - * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or - * a subclass - * @return PEAR_PackageFile_v2 - */ - function &parse($data, $file, $archive = false, $class = 'PEAR_PackageFile_v2') - { - if (PEAR::isError($err = parent::parse($data, $file))) { - return $err; - } - - $ret = new $class; - $ret->encoding = $this->encoding; - $ret->setConfig($this->_config); - if (isset($this->_logger)) { - $ret->setLogger($this->_logger); - } - - $ret->fromArray($this->_unserializedData); - $ret->setPackagefile($file, $archive); - return $ret; - } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php'; - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); - -/** - * Error code used when there is no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); - -/** - * Error code when a package name is not valid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); - -/** - * Error code used when no summary is parsed - */ -define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); - -/** - * Error code for summaries that are more than 1 line - */ -define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); - -/** - * Error code used when no description is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); - -/** - * Error code used when no license is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); - -/** - * Error code used when a version number is not present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); - -/** - * Error code used when a version number is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); - -/** - * Error code when no release notes are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); - -/** - * Error code when no maintainers are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); - -/** - * Error code when a maintainer has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); - -/** - * Error code when a maintainer has no email - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); - -/** - * Error code when a dependency is not a PHP dependency, but has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); - -/** - * Error code when a dependency has no type (pkg, php, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); - -/** - * Error code when a dependency has no relation (lt, ge, has, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); - -/** - * Error code when a dependency is not a 'has' relation, but has no version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); - -/** - * Error code when a dependency has an invalid relation - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); - -/** - * Error code when a dependency has an invalid type - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); - -/** - * Error code when a dependency has an invalid optional option - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); - -/** - * Error code when a dependency is a pkg dependency, and has an invalid package name - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); - -/** - * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); - -/** - * Error code when rel="has" and version attribute is present. - */ -define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); - -/** - * Error code when type="php" and dependency name is present - */ -define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); - -/** - * Error code when a file in the filelist has an invalid role - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); - -/** - * Error code when a file in the filelist has no role - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); - -/** - * Error code when analyzing a php source file that has parse errors - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); - -/** - * Error code when analyzing a php source file reveals a source element - * without a package name prefix - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); - -/** - * Error code when an unknown channel is specified - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); - -/** - * Error code when no files are found in the filelist - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); - -/** - * Error code when a file is not valid php according to _analyzeSourceCode() - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); - -/** - * Error code when the channel validator returns an error or warning - */ -define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); - -/** - * Error code when a php5 package is packaged in php4 (analysis doesn't work) - */ -define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); - -/** - * Error code when a file is listed in package.xml but does not exist - */ -define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); - -/** - * Error code when a - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_v1 -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * A registry object, used to access the package name validation regex for non-standard channels - * @var PEAR_Registry - * @access private - */ - var $_registry; - - /** - * An object that contains a log method that matches PEAR_Common::log's signature - * @var object - * @access private - */ - var $_logger; - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo; - - /** - * path to package.xml - * @var string - * @access private - */ - var $_packageFile; - - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string - * @access private - */ - var $_archiveFile; - - /** - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; - - /** - * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack - * @param string Name of Error Stack class to use. - */ - function PEAR_PackageFile_v1() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = 0; - } - - function installBinary($installer) - { - return false; - } - - function isExtension($name) - { - return false; - } - - function setConfig(&$config) - { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); - } - - function setRequestedGroup() - { - // placeholder - } - - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) - { - $this->_packageInfo['_lastversion'] = $version; - } - - /** - * @return string|false - */ - function getLastInstalledVersion() - { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; - } - return false; - } - - function getInstalledBinary() - { - return false; - } - - function listPostinstallScripts() - { - return false; - } - - function initPostinstallScripts() - { - return false; - } - - function setLogger(&$logger) - { - if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; - } - - function setPackagefile($file, $archive = false) - { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; - } - - function getPackageFile() - { - return isset($this->_packageFile) ? $this->_packageFile : false; - } - - function getPackageType() - { - return 'php'; - } - - function getArchiveFile() - { - return $this->_archiveFile; - } - - function packageInfo($field) - { - if (!is_string($field) || empty($field) || - !isset($this->_packageInfo[$field])) { - return false; - } - return $this->_packageInfo[$field]; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); - } - - function fromArray($pinfo) - { - $this->_incomplete = false; - $this->_packageInfo = $pinfo; - } - - function isIncomplete() - { - return $this->_incomplete; - } - - function getChannel() - { - return 'pear.php.net'; - } - - function getUri() - { - return false; - } - - function getTime() - { - return false; - } - - function getExtends() - { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; - } - - /** - * @return array - */ - function toArray() - { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray(); - } - - function getArray() - { - return $this->_packageInfo; - } - - function getName() - { - return $this->getPackage(); - } - - function getPackage() - { - if (isset($this->_packageInfo['package'])) { - return $this->_packageInfo['package']; - } - return false; - } - - /** - * WARNING - don't use this unless you know what you are doing - */ - function setRawPackage($package) - { - $this->_packageInfo['package'] = $package; - } - - function setPackage($package) - { - $this->_packageInfo['package'] = $package; - $this->_isValid = false; - } - - function getVersion() - { - if (isset($this->_packageInfo['version'])) { - return $this->_packageInfo['version']; - } - return false; - } - - function setVersion($version) - { - $this->_packageInfo['version'] = $version; - $this->_isValid = false; - } - - function clearMaintainers() - { - unset($this->_packageInfo['maintainers']); - } - - function getMaintainers() - { - if (isset($this->_packageInfo['maintainers'])) { - return $this->_packageInfo['maintainers']; - } - return false; - } - - /** - * Adds a new maintainer - no checking of duplicates is performed, use - * updatemaintainer for that purpose. - */ - function addMaintainer($role, $handle, $name, $email) - { - $this->_packageInfo['maintainers'][] = - array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); - $this->_isValid = false; - } - - function updateMaintainer($role, $handle, $name, $email) - { - $found = false; - if (!isset($this->_packageInfo['maintainers']) || - !is_array($this->_packageInfo['maintainers'])) { - return $this->addMaintainer($role, $handle, $name, $email); - } - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - } - $this->addMaintainer($role, $handle, $name, $email); - } - - function deleteMaintainer($handle) - { - $found = false; - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - return true; - } - return false; - } - - function getState() - { - if (isset($this->_packageInfo['release_state'])) { - return $this->_packageInfo['release_state']; - } - return false; - } - - function setRawState($state) - { - $this->_packageInfo['release_state'] = $state; - } - - function setState($state) - { - $this->_packageInfo['release_state'] = $state; - $this->_isValid = false; - } - - function getDate() - { - if (isset($this->_packageInfo['release_date'])) { - return $this->_packageInfo['release_date']; - } - return false; - } - - function setDate($date) - { - $this->_packageInfo['release_date'] = $date; - $this->_isValid = false; - } - - function getLicense() - { - if (isset($this->_packageInfo['release_license'])) { - return $this->_packageInfo['release_license']; - } - return false; - } - - function setLicense($date) - { - $this->_packageInfo['release_license'] = $date; - $this->_isValid = false; - } - - function getSummary() - { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; - } - - function setSummary($summary) - { - $this->_packageInfo['summary'] = $summary; - $this->_isValid = false; - } - - function getDescription() - { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; - } - - function setDescription($desc) - { - $this->_packageInfo['description'] = $desc; - $this->_isValid = false; - } - - function getNotes() - { - if (isset($this->_packageInfo['release_notes'])) { - return $this->_packageInfo['release_notes']; - } - return false; - } - - function setNotes($notes) - { - $this->_packageInfo['release_notes'] = $notes; - $this->_isValid = false; - } - - function getDeps() - { - if (isset($this->_packageInfo['release_deps'])) { - return $this->_packageInfo['release_deps']; - } - return false; - } - - /** - * Reset dependencies prior to adding new ones - */ - function clearDeps() - { - unset($this->_packageInfo['release_deps']); - } - - function addPhpDep($version, $rel) - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'php', - 'rel' => $rel, - 'version' => $version); - } - - function addPackageDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $dep = - array('type' => 'pkg', - 'name' => $name, - 'rel' => $rel, - 'optional' => $optional); - if ($rel != 'has' && $rel != 'not') { - $dep['version'] = $version; - } - $this->_packageInfo['release_deps'][] = $dep; - } - - function addExtensionDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'ext', - 'name' => $name, - 'rel' => $rel, - 'version' => $version, - 'optional' => $optional); - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) - { - $this->_packageInfo['release_deps'] = $deps; - } - - function hasDeps() - { - return isset($this->_packageInfo['release_deps']) && - count($this->_packageInfo['release_deps']); - } - - function getDependencyGroup($group) - { - return false; - } - - function isCompatible($pf) - { - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); - } - - function isSubpackage($p) - { - return false; - } - - function dependsOn($package, $channel) - { - if (strtolower($channel) != 'pear.php.net') { - return false; - } - if (!($deps = $this->getDeps())) { - return false; - } - foreach ($deps as $dep) { - if ($dep['type'] != 'pkg') { - continue; - } - if (strtolower($dep['name']) == strtolower($package)) { - return true; - } - } - return false; - } - - function getConfigureOptions() - { - if (isset($this->_packageInfo['configure_options'])) { - return $this->_packageInfo['configure_options']; - } - return false; - } - - function hasConfigureOptions() - { - return isset($this->_packageInfo['configure_options']) && - count($this->_packageInfo['configure_options']); - } - - function addConfigureOption($name, $prompt, $default = false) - { - $o = array('name' => $name, 'prompt' => $prompt); - if ($default !== false) { - $o['default'] = $default; - } - if (!isset($this->_packageInfo['configure_options'])) { - $this->_packageInfo['configure_options'] = array(); - } - $this->_packageInfo['configure_options'][] = $o; - } - - function clearConfigureOptions() - { - unset($this->_packageInfo['configure_options']); - } - - function getProvides() - { - if (isset($this->_packageInfo['provides'])) { - return $this->_packageInfo['provides']; - } - return false; - } - - function getProvidesExtension() - { - return false; - } - - function addFile($dir, $file, $attrs) - { - $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); - if ($dir == '/' || $dir == '') { - $dir = ''; - } else { - $dir .= '/'; - } - $file = $dir . $file; - $file = preg_replace('![\\/]+!', '/', $file); - $this->_packageInfo['filelist'][$file] = $attrs; - } - - function getInstallationFilelist() - { - return $this->getFilelist(); - } - - function getFilelist() - { - if (isset($this->_packageInfo['filelist'])) { - return $this->_packageInfo['filelist']; - } - return false; - } - - function setFileAttribute($file, $attr, $value) - { - $this->_packageInfo['filelist'][$file][$attr] = $value; - } - - function resetFilelist() - { - $this->_packageInfo['filelist'] = array(); - } - - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts); - } else { - $this->_packageInfo['filelist'][$file] = $atts; - } - } - - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } - - function getPackagexmlVersion() - { - return '1.0'; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) - { - return $this->_stack->getErrors($purge); - } - - // }}} - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); - $this->_isValid = false; - } - - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); - } - - /** - * @param integer error code - * @access protected - */ - function _getErrorMessage() - { - return array( - PEAR_PACKAGEFILE_ERROR_NO_NAME => - 'Missing Package Name', - PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => - 'No summary found', - PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => - 'Summary should be on one line', - PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => - 'Missing description', - PEAR_PACKAGEFILE_ERROR_NO_LICENSE => - 'Missing license', - PEAR_PACKAGEFILE_ERROR_NO_VERSION => - 'No release version found', - PEAR_PACKAGEFILE_ERROR_NO_STATE => - 'No release state found', - PEAR_PACKAGEFILE_ERROR_NO_DATE => - 'No release date found', - PEAR_PACKAGEFILE_ERROR_NO_NOTES => - 'No release notes found', - PEAR_PACKAGEFILE_ERROR_NO_LEAD => - 'Package must have at least one lead maintainer', - PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => - 'No maintainers found, at least one must be defined', - PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => - 'Maintainer %index% has no handle (user ID at channel server)', - PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => - 'Maintainer %index% has no role', - PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => - 'Maintainer %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => - 'Maintainer %index% has no email', - PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => - 'Dependency %index% is not a php dependency, and has no name', - PEAR_PACKAGEFILE_ERROR_NO_DEPREL => - 'Dependency %index% has no relation (rel)', - PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => - 'Dependency %index% has no type', - PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => - 'PHP Dependency %index% has a name attribute of "%name%" which will be' . - ' ignored!', - PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => - 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => - 'Dependency %index% is a type="php" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => - 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', - PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => - 'Dependency %index% has invalid optional value "%opt%", should be yes or no', - PEAR_PACKAGEFILE_PHP_NO_NOT => - 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . - ' to exclude specific versions', - PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => - 'Configure Option %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => - 'Configure Option %index% has no prompt', - PEAR_PACKAGEFILE_ERROR_NO_FILES => - 'No files in section of package.xml', - PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => - 'File "%file%" has no role, expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => - 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => - 'File "%file%" cannot start with ".", cannot package or install', - PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => - 'Parser error: invalid PHP found in file "%file%"', - PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => - 'in %file%: %type% "%name%" not prefixed with package name "%package%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILE => - 'Parser error: invalid PHP file "%file%"', - PEAR_PACKAGEFILE_ERROR_CHANNELVAL => - 'Channel validator error: field "%field%" - %reason%', - PEAR_PACKAGEFILE_ERROR_PHP5 => - 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', - PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => - 'File "%file%" in package.xml does not exist', - PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => - 'Package.xml contains non-ISO-8859-1 characters, and may not validate', - ); - } - - /** - * Validate XML package definition file. - * - * @access public - * @return boolean - */ - function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) - { - if (($this->_isValid & $state) == $state) { - return true; - } - $this->_isValid = true; - $info = $this->_packageInfo; - if (empty($info['package'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); - $this->_packageName = $pn = 'unknown'; - } else { - $this->_packageName = $pn = $info['package']; - } - - if (empty($info['summary'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (empty($info['description'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); - } - if (empty($info['release_license'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); - } - if (empty($info['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); - } - if (empty($info['release_state'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); - } - if (empty($info['release_date'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); - } - if (empty($info['release_notes'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); - } - if (empty($info['maintainers'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); - } else { - $haslead = false; - $i = 1; - foreach ($info['maintainers'] as $m) { - if (empty($m['handle'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, - array('index' => $i)); - } - if (empty($m['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, - array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); - } elseif ($m['role'] == 'lead') { - $haslead = true; - } - if (empty($m['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, - array('index' => $i)); - } - if (empty($m['email'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, - array('index' => $i)); - } - $i++; - } - if (!$haslead) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); - } - } - if (!empty($info['release_deps'])) { - $i = 1; - foreach ($info['release_deps'] as $d) { - if (!isset($d['type']) || empty($d['type'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, - array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); - continue; - } - if (!isset($d['rel']) || empty($d['rel'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, - array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); - continue; - } - if (!empty($d['optional'])) { - if (!in_array($d['optional'], array('yes', 'no'))) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, - array('index' => $i, 'opt' => $d['optional'])); - } - } - if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, - array('index' => $i)); - } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, - array('index' => $i, 'rel' => $d['rel'])); - } - if ($d['type'] == 'php' && !empty($d['name'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, - array('index' => $i, 'name' => $d['name'])); - } elseif ($d['type'] != 'php' && empty($d['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, - array('index' => $i)); - } - if ($d['type'] == 'php' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, - array('index' => $i)); - } - if (($d['rel'] == 'not') && ($d['type'] == 'php')) { - $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, - array('index' => $i)); - } - $i++; - } - } - if (!empty($info['configure_options'])) { - $i = 1; - foreach ($info['configure_options'] as $c) { - if (empty($c['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, - array('index' => $i)); - } - if (empty($c['prompt'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, - array('index' => $i)); - } - $i++; - } - } - if (empty($info['filelist'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); - $errors[] = 'no files'; - } else { - foreach ($info['filelist'] as $file => $fa) { - if (empty($fa['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, - array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); - continue; - } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, - array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { - // file contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file)); - } - if (isset($fa['install-as']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['install-as']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); - } - if (isset($fa['baseinstalldir']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['baseinstalldir']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); - } - } - } - if (isset($this->_registry) && $this->_isValid) { - $chan = $this->_registry->getChannel('pear.php.net'); - if (PEAR::isError($chan)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); - return $this->_isValid = 0; - } - $validator = $chan->getValidationObject(); - $validator->setPackageFile($this); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); - } - foreach ($failures['warnings'] as $warning) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); - } - } - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { - if ($this->_analyzePhpFiles()) { - $this->_isValid = true; - } - } - if ($this->_isValid) { - return $this->_isValid = $state; - } - return $this->_isValid = 0; - } - - function _analyzePhpFiles() - { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_packageFile)) { - return false; - } - $dir_prefix = dirname($this->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_logger) ? array(&$this->_logger, 'log') : - array($common, 'log'); - $info = $this->getFilelist(); - foreach ($info as $file => $fa) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, - array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); - continue; - } - if ($fa['role'] == 'php' && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $this->_buildProvidesArray($srcinfo); - } - } - } - $this->_packageName = $pn = $this->getPackage(); - $pnl = strlen($pn); - if (isset($this->_packageInfo['provides'])) { - foreach ((array) $this->_packageInfo['provides'] as $key => $what) { - if (isset($what['explicit'])) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } - } - } - return $this->_isValid; - } - - /** - * Get the default xml generator object - * - * @return PEAR_PackageFile_Generator_v1 - */ - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v1')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v1.php'; - } - $a = &new PEAR_PackageFile_Generator_v1($this); - return $a; - } - - /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string - */ - function getFileContents($file) - { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - if (!class_exists('Archive_Tar')) { - require_once 'phar://go-pear.phar/' . 'Archive/Tar.php'; - } - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - // {{{ analyzeSourceCode() - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access private - */ - function _analyzeSourceCode($file) - { - if (!function_exists("token_get_all")) { - return false; - } - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); - } - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); - } - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); - } - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); - $tokens = token_get_all($contents); -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); - } - } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; - } - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; - } - } - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - )) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, - array($file)); - } - } - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; - } - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } - } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; - } - continue 2; - } - } - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * - */ - function _buildProvidesArray($srcinfo) - { - if (!$this->_isValid) { - return false; - } - $file = basename($srcinfo['source_file']); - $pn = $this->getPackage(); - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->_packageInfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { - continue; - } - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - // }}} -} -?> - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling - */ -require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_v2 -{ - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo = array(); - - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string|false - * @access private - */ - var $_archiveFile; - - /** - * path to package .xml or false if this is an abstract parsed-from-string xml - * @var string|false - * @access private - */ - var $_packageFile; - - /** - * This is used by file analysis routines to log progress information - * @var PEAR_Common - * @access protected - */ - var $_logger; - - /** - * This is set to the highest validation level that has been validated - * - * If the package.xml is invalid or unknown, this is set to 0. If - * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If - * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING - * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation - * "caching" to occur, which is particularly important for package validation, so - * that PHP files are not validated twice - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * True if the filelist has been validated - * @param bool - */ - var $_filesValid = false; - - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * @var PEAR_Config - * @access protected - */ - var $_config; - - /** - * Optional Dependency group requested for installation - * @var string - * @access private - */ - var $_requestedGroup = false; - - /** - * @var PEAR_ErrorStack - * @access protected - */ - var $_stack; - - /** - * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible - */ - var $_tasksNs; - - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; - - /** - * @var PEAR_PackageFile_v2_Validator - */ - var $_v2Validator; - - /** - * The constructor merely sets up the private error stack - */ - function PEAR_PackageFile_v2() - { - $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); - $this->_isValid = false; - } - - /** - * To make unit-testing easier - * @param PEAR_Frontend_* - * @param array options - * @param PEAR_Config - * @return PEAR_Downloader - * @access protected - */ - function &getPEARDownloader(&$i, $o, &$c) - { - $z = &new PEAR_Downloader($i, $o, $c); - return $z; - } - - /** - * To make unit-testing easier - * @param PEAR_Config - * @param array options - * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} - * @param int PEAR_VALIDATE_* constant - * @return PEAR_Dependency2 - * @access protected - */ - function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) - { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php'; - } - $z = &new PEAR_Dependency2($c, $o, $p, $s); - return $z; - } - - function getInstalledBinary() - { - return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : - false; - } - - /** - * Installation of source package has failed, attempt to download and install the - * binary version of this package. - * @param PEAR_Installer - * @return array|false - */ - function installBinary(&$installer) - { - if (!OS_WINDOWS) { - $a = false; - return $a; - } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $releasetype = $this->getPackageType() . 'release'; - if (!is_array($installer->getInstallPackages())) { - $a = false; - return $a; - } - foreach ($installer->getInstallPackages() as $p) { - if ($p->isExtension($this->_packageInfo['providesextension'])) { - if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { - $a = false; - return $a; // the user probably downloaded it separately - } - } - } - if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { - $installer->log(0, 'Attempting to download binary version of extension "' . - $this->_packageInfo['providesextension'] . '"'); - $params = $this->_packageInfo[$releasetype]['binarypackage']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); - } - if (isset($this->_packageInfo['channel'])) { - foreach ($params as $i => $param) { - $params[$i] = array('channel' => $this->_packageInfo['channel'], - 'package' => $param, 'version' => $this->getVersion()); - } - } - $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), - $installer->config); - $verbose = $dl->config->get('verbose'); - $dl->config->set('verbose', -1); - foreach ($params as $param) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $dl->download(array($param)); - PEAR::popErrorHandling(); - if (is_array($ret) && count($ret)) { - break; - } - } - $dl->config->set('verbose', $verbose); - if (is_array($ret)) { - if (count($ret) == 1) { - $pf = $ret[0]->getPackageFile(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $installer->install($ret[0]); - PEAR::popErrorHandling(); - if (is_array($err)) { - $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); - // "install" self, so all dependencies will work transparently - $this->_registry->addPackage2($this); - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" successful'); - $a = array($ret[0], $err); - return $a; - } - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" failed'); - } - } - } - } - $a = false; - return $a; - } - - /** - * @return string|false Extension name - */ - function getProvidesExtension() - { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - if (isset($this->_packageInfo['providesextension'])) { - return $this->_packageInfo['providesextension']; - } - } - return false; - } - - /** - * @param string Extension name - * @return bool - */ - function isExtension($extension) - { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - return $this->_packageInfo['providesextension'] == $extension; - } - return false; - } - - /** - * Tests whether every part of the package.xml 1.0 is represented in - * this package.xml 2.0 - * @param PEAR_PackageFile_v1 - * @return bool - */ - function isEquivalent($pf1) - { - if (!$pf1) { - return true; - } - if ($this->getPackageType() == 'bundle') { - return false; - } - $this->_stack->getErrors(true); - if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - $pass = true; - if ($pf1->getPackage() != $this->getPackage()) { - $this->_differentPackage($pf1->getPackage()); - $pass = false; - } - if ($pf1->getVersion() != $this->getVersion()) { - $this->_differentVersion($pf1->getVersion()); - $pass = false; - } - if (trim($pf1->getSummary()) != $this->getSummary()) { - $this->_differentSummary($pf1->getSummary()); - $pass = false; - } - if (preg_replace('/\s+/', '', $pf1->getDescription()) != - preg_replace('/\s+/', '', $this->getDescription())) { - $this->_differentDescription($pf1->getDescription()); - $pass = false; - } - if ($pf1->getState() != $this->getState()) { - $this->_differentState($pf1->getState()); - $pass = false; - } - if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), - preg_replace('/\s+/', '', $pf1->getNotes()))) { - $this->_differentNotes($pf1->getNotes()); - $pass = false; - } - $mymaintainers = $this->getMaintainers(); - $yourmaintainers = $pf1->getMaintainers(); - for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { - $reset = false; - for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { - if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { - if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { - $this->_differentRole($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); - $pass = false; - } - if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { - $this->_differentEmail($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); - $pass = false; - } - if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { - $this->_differentName($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); - $pass = false; - } - unset($mymaintainers[$i2]); - $mymaintainers = array_values($mymaintainers); - unset($yourmaintainers[$i1]); - $yourmaintainers = array_values($yourmaintainers); - $reset = true; - break; - } - } - if ($reset) { - $i1 = -1; - } - } - $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); - $filelist = $this->getFilelist(); - foreach ($pf1->getFilelist() as $file => $atts) { - if (!isset($filelist[$file])) { - $this->_missingFile($file); - $pass = false; - } - } - return $pass; - } - - function _differentPackage($package) - { - $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, - 'self' => $this->getPackage()), - 'package.xml 1.0 package "%package%" does not match "%self%"'); - } - - function _differentVersion($version) - { - $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, - 'self' => $this->getVersion()), - 'package.xml 1.0 version "%version%" does not match "%self%"'); - } - - function _differentState($state) - { - $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, - 'self' => $this->getState()), - 'package.xml 1.0 state "%state%" does not match "%self%"'); - } - - function _differentRole($handle, $role, $selfrole) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'role' => $role, 'self' => $selfrole), - 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); - } - - function _differentEmail($handle, $email, $selfemail) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'email' => $email, 'self' => $selfemail), - 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); - } - - function _differentName($handle, $name, $selfname) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'name' => $name, 'self' => $selfname), - 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); - } - - function _unmatchedMaintainers($my, $yours) - { - if ($my) { - array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), - 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); - } - if ($yours) { - array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), - 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); - } - } - - function _differentNotes($notes) - { - $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; - $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : - substr($this->getNotes(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, - 'self' => $truncmynotes), - 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); - } - - function _differentSummary($summary) - { - $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; - $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : - substr($this->getsummary(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, - 'self' => $truncmysummary), - 'package.xml 1.0 summary "%summary%" does not match "%self%"'); - } - - function _differentDescription($description) - { - $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); - $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : - substr($this->getdescription(), 0, 24) . '...'); - $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, - 'self' => $truncmydescription), - 'package.xml 1.0 description "%description%" does not match "%self%"'); - } - - function _missingFile($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'package.xml 1.0 file "%file%" is not present in '); - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawState($state) - { - if (!isset($this->_packageInfo['stability'])) { - $this->_packageInfo['stability'] = array(); - } - $this->_packageInfo['stability']['release'] = $state; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawCompatible($compatible) - { - $this->_packageInfo['compatible'] = $compatible; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawPackage($package) - { - $this->_packageInfo['name'] = $package; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawChannel($channel) - { - $this->_packageInfo['channel'] = $channel; - } - - function setRequestedGroup($group) - { - $this->_requestedGroup = $group; - } - - function getRequestedGroup() - { - if (isset($this->_requestedGroup)) { - return $this->_requestedGroup; - } - return false; - } - - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) - { - $this->_packageInfo['_lastversion'] = $version; - } - - /** - * @return string|false - */ - function getLastInstalledVersion() - { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; - } - return false; - } - - /** - * Determines whether this package.xml has post-install scripts or not - * @return array|false - */ - function listPostinstallScripts() - { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); - } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; - } - } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - $ret = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // ignored files will not be in the filelist - continue; - } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $task = $this->getTask($tag); - $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); - if ($task->isScript()) { - $ret[] = $filelist[$name]['installed_as']; - } - } - } - if (count($ret)) { - return $ret; - } - return false; - } - - /** - * Initialize post-install scripts for running - * - * This method can be used to detect post-install scripts, as the return value - * indicates whether any exist - * @return bool - */ - function initPostinstallScripts() - { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); - } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; - } - } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // file was not installed due to installconditions - continue; - } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $taskname = $this->getTask($tag); - $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); - if (!$task->isScript()) { - continue; // scripts are only handled after installation - } - $lastversion = isset($this->_packageInfo['_lastversion']) ? - $this->_packageInfo['_lastversion'] : null; - $task->init($raw, $atts, $lastversion); - $res = $task->startSession($this, $atts['installed_as']); - if (!$res) { - continue; // skip this file - } - if (PEAR::isError($res)) { - return $res; - } - $assign = &$task; - $this->_scripts[] = &$assign; - } - } - if (count($this->_scripts)) { - return true; - } - return false; - } - - function runPostinstallScripts() - { - if ($this->initPostinstallScripts()) { - $ui = &PEAR_Frontend::singleton(); - if ($ui) { - $ui->runPostinstallScripts($this->_scripts, $this); - } - } - } - - - /** - * Convert a recursive set of and tags into a single tag with - * tags. - */ - function flattenFilelist() - { - if (isset($this->_packageInfo['bundle'])) { - return; - } - $filelist = array(); - if (isset($this->_packageInfo['contents']['dir']['dir'])) { - $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); - if (!isset($filelist[1])) { - $filelist = $filelist[0]; - } - $this->_packageInfo['contents']['dir']['file'] = $filelist; - unset($this->_packageInfo['contents']['dir']['dir']); - } else { - // else already flattened but check for baseinstalldir propagation - if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { - if (isset($this->_packageInfo['contents']['dir']['file'][0])) { - foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { - if (isset($file['attribs']['baseinstalldir'])) { - continue; - } - $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } else { - if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { - $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } - } - } - } - - /** - * @param array the final flattened file list - * @param array the current directory being processed - * @param string|false any recursively inherited baeinstalldir attribute - * @param string private recursion variable - * @return array - * @access protected - */ - function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') - { - if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { - $baseinstall = $dir['attribs']['baseinstalldir']; - } - if (isset($dir['dir'])) { - if (!isset($dir['dir'][0])) { - $dir['dir'] = array($dir['dir']); - } - foreach ($dir['dir'] as $subdir) { - if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { - $name = '*unknown*'; - } else { - $name = $subdir['attribs']['name']; - } - $newpath = empty($path) ? $name : - $path . '/' . $name; - $this->_getFlattenedFilelist($files, $subdir, - $baseinstall, $newpath); - } - } - if (isset($dir['file'])) { - if (!isset($dir['file'][0])) { - $dir['file'] = array($dir['file']); - } - foreach ($dir['file'] as $file) { - $attrs = $file['attribs']; - $name = $attrs['name']; - if ($baseinstall && !isset($attrs['baseinstalldir'])) { - $attrs['baseinstalldir'] = $baseinstall; - } - $attrs['name'] = empty($path) ? $name : $path . '/' . $name; - $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attrs['name']); - $file['attribs'] = $attrs; - $files[] = $file; - } - } - } - - function setConfig(&$config) - { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); - } - - function setLogger(&$logger) - { - if (!is_object($logger) || !method_exists($logger, 'log')) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) - { - $this->_packageInfo['dependencies'] = $deps; - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setCompatible($compat) - { - $this->_packageInfo['compatible'] = $compat; - } - - function setPackagefile($file, $archive = false) - { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) - { - return $this->_stack->getErrors($purge); - } - - function getPackageFile() - { - return $this->_packageFile; - } - - function getArchiveFile() - { - return $this->_archiveFile; - } - - - /** - * Directly set the array that defines this packagefile - * - * WARNING: no validation. This should only be performed by internal methods - * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 - * @param array - */ - function fromArray($pinfo) - { - unset($pinfo['old']); - unset($pinfo['xsdversion']); - $this->_incomplete = false; - $this->_packageInfo = $pinfo; - } - - function isIncomplete() - { - return $this->_incomplete; - } - - /** - * @return array - */ - function toArray($forreg = false) - { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray($forreg); - } - - function getArray($forReg = false) - { - if ($forReg) { - $arr = $this->_packageInfo; - $arr['old'] = array(); - $arr['old']['version'] = $this->getVersion(); - $arr['old']['release_date'] = $this->getDate(); - $arr['old']['release_state'] = $this->getState(); - $arr['old']['release_license'] = $this->getLicense(); - $arr['old']['release_notes'] = $this->getNotes(); - $arr['old']['release_deps'] = $this->getDeps(); - $arr['old']['maintainers'] = $this->getMaintainers(); - $arr['xsdversion'] = '2.0'; - return $arr; - } else { - $info = $this->_packageInfo; - unset($info['dirtree']); - if (isset($info['_lastversion'])) { - unset($info['_lastversion']); - } - if (isset($info['#binarypackage'])) { - unset($info['#binarypackage']); - } - return $info; - } - } - - function packageInfo($field) - { - $arr = $this->getArray(true); - if ($field == 'state') { - return $arr['stability']['release']; - } - if ($field == 'api-version') { - return $arr['version']['api']; - } - if ($field == 'api-state') { - return $arr['stability']['api']; - } - if (isset($arr['old'][$field])) { - if (!is_string($arr['old'][$field])) { - return null; - } - return $arr['old'][$field]; - } - if (isset($arr[$field])) { - if (!is_string($arr[$field])) { - return null; - } - return $arr[$field]; - } - return null; - } - - function getName() - { - return $this->getPackage(); - } - - function getPackage() - { - if (isset($this->_packageInfo['name'])) { - return $this->_packageInfo['name']; - } - return false; - } - - function getChannel() - { - if (isset($this->_packageInfo['uri'])) { - return '__uri'; - } - if (isset($this->_packageInfo['channel'])) { - return strtolower($this->_packageInfo['channel']); - } - return false; - } - - function getUri() - { - if (isset($this->_packageInfo['uri'])) { - return $this->_packageInfo['uri']; - } - return false; - } - - function getExtends() - { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; - } - - function getSummary() - { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; - } - - function getDescription() - { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; - } - - function getMaintainers($raw = false) - { - if (!isset($this->_packageInfo['lead'])) { - return false; - } - if ($raw) { - $ret = array('lead' => $this->_packageInfo['lead']); - (isset($this->_packageInfo['developer'])) ? - $ret['developer'] = $this->_packageInfo['developer'] :null; - (isset($this->_packageInfo['contributor'])) ? - $ret['contributor'] = $this->_packageInfo['contributor'] :null; - (isset($this->_packageInfo['helper'])) ? - $ret['helper'] = $this->_packageInfo['helper'] :null; - return $ret; - } else { - $ret = array(); - $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : - array($this->_packageInfo['lead']); - foreach ($leads as $lead) { - $s = $lead; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'lead'; - $ret[] = $s; - } - if (isset($this->_packageInfo['developer'])) { - $leads = isset($this->_packageInfo['developer'][0]) ? - $this->_packageInfo['developer'] : - array($this->_packageInfo['developer']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'developer'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['contributor'])) { - $leads = isset($this->_packageInfo['contributor'][0]) ? - $this->_packageInfo['contributor'] : - array($this->_packageInfo['contributor']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'contributor'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['helper'])) { - $leads = isset($this->_packageInfo['helper'][0]) ? - $this->_packageInfo['helper'] : - array($this->_packageInfo['helper']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'helper'; - $ret[] = $s; - } - } - return $ret; - } - return false; - } - - function getLeads() - { - if (isset($this->_packageInfo['lead'])) { - return $this->_packageInfo['lead']; - } - return false; - } - - function getDevelopers() - { - if (isset($this->_packageInfo['developer'])) { - return $this->_packageInfo['developer']; - } - return false; - } - - function getContributors() - { - if (isset($this->_packageInfo['contributor'])) { - return $this->_packageInfo['contributor']; - } - return false; - } - - function getHelpers() - { - if (isset($this->_packageInfo['helper'])) { - return $this->_packageInfo['helper']; - } - return false; - } - - function setDate($date) - { - if (!isset($this->_packageInfo['date'])) { - // ensure that the extends tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); - } - $this->_packageInfo['date'] = $date; - $this->_isValid = 0; - } - - function setTime($time) - { - $this->_isValid = 0; - if (!isset($this->_packageInfo['time'])) { - // ensure that the time tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); - } - $this->_packageInfo['time'] = $time; - } - - function getDate() - { - if (isset($this->_packageInfo['date'])) { - return $this->_packageInfo['date']; - } - return false; - } - - function getTime() - { - if (isset($this->_packageInfo['time'])) { - return $this->_packageInfo['time']; - } - return false; - } - - /** - * @param package|api version category to return - */ - function getVersion($key = 'release') - { - if (isset($this->_packageInfo['version'][$key])) { - return $this->_packageInfo['version'][$key]; - } - return false; - } - - function getStability() - { - if (isset($this->_packageInfo['stability'])) { - return $this->_packageInfo['stability']; - } - return false; - } - - function getState($key = 'release') - { - if (isset($this->_packageInfo['stability'][$key])) { - return $this->_packageInfo['stability'][$key]; - } - return false; - } - - function getLicense($raw = false) - { - if (isset($this->_packageInfo['license'])) { - if ($raw) { - return $this->_packageInfo['license']; - } - if (is_array($this->_packageInfo['license'])) { - return $this->_packageInfo['license']['_content']; - } else { - return $this->_packageInfo['license']; - } - } - return false; - } - - function getLicenseLocation() - { - if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { - return false; - } - return $this->_packageInfo['license']['attribs']; - } - - function getNotes() - { - if (isset($this->_packageInfo['notes'])) { - return $this->_packageInfo['notes']; - } - return false; - } - - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsesrole() - { - if (isset($this->_packageInfo['usesrole'])) { - return $this->_packageInfo['usesrole']; - } - return false; - } - - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsestask() - { - if (isset($this->_packageInfo['usestask'])) { - return $this->_packageInfo['usestask']; - } - return false; - } - - /** - * This should only be used to retrieve filenames and install attributes - */ - function getFilelist($preserve = false) - { - if (isset($this->_packageInfo['filelist']) && !$preserve) { - return $this->_packageInfo['filelist']; - } - $this->flattenFilelist(); - if ($contents = $this->getContents()) { - $ret = array(); - if (!isset($contents['dir'])) { - return false; - } - if (!isset($contents['dir']['file'][0])) { - $contents['dir']['file'] = array($contents['dir']['file']); - } - foreach ($contents['dir']['file'] as $file) { - $name = $file['attribs']['name']; - if (!$preserve) { - $file = $file['attribs']; - } - $ret[$name] = $file; - } - if (!$preserve) { - $this->_packageInfo['filelist'] = $ret; - } - return $ret; - } - return false; - } - - /** - * Return configure options array, if any - * - * @return array|false - */ - function getConfigureOptions() - { - if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { - return false; - } - - $releases = $this->getReleases(); - if (isset($releases[0])) { - $releases = $releases[0]; - } - - if (isset($releases['configureoption'])) { - if (!isset($releases['configureoption'][0])) { - $releases['configureoption'] = array($releases['configureoption']); - } - - for ($i = 0; $i < count($releases['configureoption']); $i++) { - $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; - } - - return $releases['configureoption']; - } - - return false; - } - - /** - * This is only used at install-time, after all serialization - * is over. - */ - function resetFilelist() - { - $this->_packageInfo['filelist'] = array(); - } - - /** - * Retrieve a list of files that should be installed on this computer - * @return array - */ - function getInstallationFilelist($forfilecheck = false) - { - $contents = $this->getFilelist(true); - if (isset($contents['dir']['attribs']['baseinstalldir'])) { - $base = $contents['dir']['attribs']['baseinstalldir']; - } - if (isset($this->_packageInfo['bundle'])) { - return PEAR::raiseError( - 'Exception: bundles should be handled in download code only'); - } - $release = $this->getReleases(); - if ($release) { - if (!isset($release[0])) { - if (!isset($release['installconditions']) && !isset($release['filelist'])) { - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - $release = array($release); - } - $depchecker = &$this->getPEARDependency2($this->_config, array(), - array('channel' => $this->getChannel(), 'package' => $this->getPackage()), - PEAR_VALIDATE_INSTALLING); - foreach ($release as $instance) { - if (isset($instance['installconditions'])) { - $installconditions = $instance['installconditions']; - if (is_array($installconditions)) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($installconditions as $type => $conditions) { - if (!isset($conditions[0])) { - $conditions = array($conditions); - } - foreach ($conditions as $condition) { - $ret = $depchecker->{"validate{$type}Dependency"}($condition); - if (PEAR::isError($ret)) { - PEAR::popErrorHandling(); - continue 3; // skip this release - } - } - } - PEAR::popErrorHandling(); - } - } - // this is the release to use - if (isset($instance['filelist'])) { - // ignore files - if (isset($instance['filelist']['ignore'])) { - $ignore = isset($instance['filelist']['ignore'][0]) ? - $instance['filelist']['ignore'] : - array($instance['filelist']['ignore']); - foreach ($ignore as $ig) { - unset ($contents[$ig['attribs']['name']]); - } - } - // install files as this name - if (isset($instance['filelist']['install'])) { - $installas = isset($instance['filelist']['install'][0]) ? - $instance['filelist']['install'] : - array($instance['filelist']['install']); - foreach ($installas as $as) { - $contents[$as['attribs']['name']]['attribs']['install-as'] = - $as['attribs']['as']; - } - } - } - if ($forfilecheck) { - foreach ($contents as $file => $attrs) { - $contents[$file] = $attrs['attribs']; - } - } - return $contents; - } - } else { // simple release - no installconditions or install-as - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - // no releases matched - return PEAR::raiseError('No releases in package.xml matched the existing operating ' . - 'system, extensions installed, or architecture, cannot install'); - } - - /** - * This is only used at install-time, after all serialization - * is over. - * @param string file name - * @param string installed path - */ - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function getInstalledLocation($file) - { - if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { - return $this->_packageInfo['filelist'][$file]['installed_as']; - } - return false; - } - - /** - * This is only used at install-time, after all serialization - * is over. - */ - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); - } else { - $this->_packageInfo['filelist'][$file] = $atts['attribs']; - } - } - - /** - * Retrieve the contents tag - */ - function getContents() - { - if (isset($this->_packageInfo['contents'])) { - return $this->_packageInfo['contents']; - } - return false; - } - - /** - * @param string full path to file - * @param string attribute name - * @param string attribute value - * @param int risky but fast - use this to choose a file based on its position in the list - * of files. Index is zero-based like PHP arrays. - * @return bool success of operation - */ - function setFileAttribute($filename, $attr, $value, $index = false) - { - $this->_isValid = 0; - if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { - $this->_filesValid = false; - } - if ($index !== false && - isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { - $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; - return true; - } - if (!isset($this->_packageInfo['contents']['dir']['file'])) { - return false; - } - $files = $this->_packageInfo['contents']['dir']['file']; - if (!isset($files[0])) { - $files = array($files); - $ind = false; - } else { - $ind = true; - } - foreach ($files as $i => $file) { - if (isset($file['attribs'])) { - if ($file['attribs']['name'] == $filename) { - if ($ind) { - $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; - } else { - $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; - } - return true; - } - } - } - return false; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); - } - - /** - * Determines whether this package claims it is compatible with the version of - * the package that has a recommended version dependency - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package - * @return boolean - */ - function isCompatible($pf) - { - if (!isset($this->_packageInfo['compatible'])) { - return false; - } - if (!isset($this->_packageInfo['channel'])) { - return false; - } - $me = $pf->getVersion(); - $compatible = $this->_packageInfo['compatible']; - if (!isset($compatible[0])) { - $compatible = array($compatible); - } - $found = false; - foreach ($compatible as $info) { - if (strtolower($info['name']) == strtolower($pf->getPackage())) { - if (strtolower($info['channel']) == strtolower($pf->getChannel())) { - $found = true; - break; - } - } - } - if (!$found) { - return false; - } - if (isset($info['exclude'])) { - if (!isset($info['exclude'][0])) { - $info['exclude'] = array($info['exclude']); - } - foreach ($info['exclude'] as $exclude) { - if (version_compare($me, $exclude, '==')) { - return false; - } - } - } - if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { - return true; - } - return false; - } - - /** - * @return array|false - */ - function getCompatible() - { - if (isset($this->_packageInfo['compatible'])) { - return $this->_packageInfo['compatible']; - } - return false; - } - - function getDependencies() - { - if (isset($this->_packageInfo['dependencies'])) { - return $this->_packageInfo['dependencies']; - } - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); - } - - /** - * Determines whether the passed in package is a subpackage of this package. - * - * No version checking is done, only name verification. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - */ - function isSubpackage($p) - { - $sub = array(); - if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { - $sub = $this->_packageInfo['dependencies']['required']['subpackage']; - if (!isset($sub[0])) { - $sub = array($sub); - } - } - if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { - $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; - if (!isset($sub1[0])) { - $sub1 = array($sub1); - } - $sub = array_merge($sub, $sub1); - } - if (isset($this->_packageInfo['dependencies']['group'])) { - $group = $this->_packageInfo['dependencies']['group']; - if (!isset($group[0])) { - $group = array($group); - } - foreach ($group as $deps) { - if (isset($deps['subpackage'])) { - $sub2 = $deps['subpackage']; - if (!isset($sub2[0])) { - $sub2 = array($sub2); - } - $sub = array_merge($sub, $sub2); - } - } - } - foreach ($sub as $dep) { - if (strtolower($dep['name']) == strtolower($p->getPackage())) { - if (isset($dep['channel'])) { - if (strtolower($dep['channel']) == strtolower($p->getChannel())) { - return true; - } - } else { - if ($dep['uri'] == $p->getURI()) { - return true; - } - } - } - } - return false; - } - - function dependsOn($package, $channel) - { - if (!($deps = $this->getDependencies())) { - return false; - } - foreach (array('package', 'subpackage') as $type) { - foreach (array('required', 'optional') as $needed) { - if (isset($deps[$needed][$type])) { - if (!isset($deps[$needed][$type][0])) { - $deps[$needed][$type] = array($deps[$needed][$type]); - } - foreach ($deps[$needed][$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } - } - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $dep['group'] = array($deps['group']); - } - foreach ($deps['group'] as $group) { - if (isset($group[$type])) { - if (!is_array($group[$type])) { - $group[$type] = array($group[$type]); - } - foreach ($group[$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } - } - } - } - return false; - } - - /** - * Get the contents of a dependency group - * @param string - * @return array|false - */ - function getDependencyGroup($name) - { - $name = strtolower($name); - if (!isset($this->_packageInfo['dependencies']['group'])) { - return false; - } - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } - foreach ($groups as $group) { - if (strtolower($group['attribs']['name']) == $name) { - return $group; - } - } - return false; - } - - /** - * Retrieve a partial package.xml 1.0 representation of dependencies - * - * a very limited representation of dependencies is returned by this method. - * The tag for excluding certain versions of a dependency is - * completely ignored. In addition, dependency groups are ignored, with the - * assumption that all dependencies in dependency groups are also listed in - * the optional group that work with all dependency groups - * @param boolean return package.xml 2.0 tag - * @return array|false - */ - function getDeps($raw = false, $nopearinstaller = false) - { - if (isset($this->_packageInfo['dependencies'])) { - if ($raw) { - return $this->_packageInfo['dependencies']; - } - $ret = array(); - $map = array( - 'php' => 'php', - 'package' => 'pkg', - 'subpackage' => 'pkg', - 'extension' => 'ext', - 'os' => 'os', - 'pearinstaller' => 'pkg', - ); - foreach (array('required', 'optional') as $type) { - $optional = ($type == 'optional') ? 'yes' : 'no'; - if (!isset($this->_packageInfo['dependencies'][$type]) - || empty($this->_packageInfo['dependencies'][$type])) { - continue; - } - foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { - if ($dtype == 'pearinstaller' && $nopearinstaller) { - continue; - } - if (!isset($deps[0])) { - $deps = array($deps); - } - foreach ($deps as $dep) { - if (!isset($map[$dtype])) { - // no support for arch type - continue; - } - if ($dtype == 'pearinstaller') { - $dep['name'] = 'PEAR'; - $dep['channel'] = 'pear.php.net'; - } - $s = array('type' => $map[$dtype]); - if (isset($dep['channel'])) { - $s['channel'] = $dep['channel']; - } - if (isset($dep['uri'])) { - $s['uri'] = $dep['uri']; - } - if (isset($dep['name'])) { - $s['name'] = $dep['name']; - } - if (isset($dep['conflicts'])) { - $s['rel'] = 'not'; - } else { - if (!isset($dep['min']) && - !isset($dep['max'])) { - $s['rel'] = 'has'; - $s['optional'] = $optional; - } elseif (isset($dep['min']) && - isset($dep['max'])) { - $s['rel'] = 'ge'; - $s1 = $s; - $s1['rel'] = 'le'; - $s['version'] = $dep['min']; - $s1['version'] = $dep['max']; - if (isset($dep['channel'])) { - $s1['channel'] = $dep['channel']; - } - if ($dtype != 'php') { - $s['name'] = $dep['name']; - $s1['name'] = $dep['name']; - } - $s['optional'] = $optional; - $s1['optional'] = $optional; - $ret[] = $s1; - } elseif (isset($dep['min'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['min']) { - $s['rel'] = 'gt'; - } else { - $s['rel'] = 'ge'; - } - $s['version'] = $dep['min']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } elseif (isset($dep['max'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['max']) { - $s['rel'] = 'lt'; - } else { - $s['rel'] = 'le'; - } - $s['version'] = $dep['max']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } - } - $ret[] = $s; - } - } - } - if (count($ret)) { - return $ret; - } - } - return false; - } - - /** - * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false - */ - function getPackageType() - { - if (isset($this->_packageInfo['phprelease'])) { - return 'php'; - } - if (isset($this->_packageInfo['extsrcrelease'])) { - return 'extsrc'; - } - if (isset($this->_packageInfo['extbinrelease'])) { - return 'extbin'; - } - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return 'zendextsrc'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return 'zendextbin'; - } - if (isset($this->_packageInfo['bundle'])) { - return 'bundle'; - } - return false; - } - - /** - * @return array|false - */ - function getReleases() - { - $type = $this->getPackageType(); - if ($type != 'bundle') { - $type .= 'release'; - } - if ($this->getPackageType() && isset($this->_packageInfo[$type])) { - return $this->_packageInfo[$type]; - } - return false; - } - - /** - * @return array - */ - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } - - function hasDeps() - { - return isset($this->_packageInfo['dependencies']); - } - - function getPackagexmlVersion() - { - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return '2.1'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return '2.1'; - } - return '2.0'; - } - - /** - * @return array|false - */ - function getSourcePackage() - { - if (isset($this->_packageInfo['extbinrelease']) || - isset($this->_packageInfo['zendextbinrelease'])) { - return array('channel' => $this->_packageInfo['srcchannel'], - 'package' => $this->_packageInfo['srcpackage']); - } - return false; - } - - function getBundledPackages() - { - if (isset($this->_packageInfo['bundle'])) { - return $this->_packageInfo['contents']['bundledpackage']; - } - return false; - } - - function getLastModified() - { - if (isset($this->_packageInfo['_lastmodified'])) { - return $this->_packageInfo['_lastmodified']; - } - return false; - } - - /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string - */ - function getFileContents($file) - { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - function &getRW() - { - if (!class_exists('PEAR_PackageFile_v2_rw')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/rw.php'; - } - $a = new PEAR_PackageFile_v2_rw; - foreach (get_object_vars($this) as $name => $unused) { - if (!isset($this->$name)) { - continue; - } - if ($name == '_config' || $name == '_logger'|| $name == '_registry' || - $name == '_stack') { - $a->$name = &$this->$name; - } else { - $a->$name = $this->$name; - } - } - return $a; - } - - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v2.php'; - } - $a = &new PEAR_PackageFile_Generator_v2($this); - return $a; - } - - function analyzeSourceCode($file, $string = false) - { - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/Validator.php'; - } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; - } - return $this->_v2Validator->analyzeSourceCode($file, $string); - } - - function validate($state = PEAR_VALIDATE_NORMAL) - { - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { - return false; - } - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/Validator.php'; - } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; - } - if (isset($this->_packageInfo['xsdversion'])) { - unset($this->_packageInfo['xsdversion']); - } - return $this->_v2Validator->validate($this, $state); - } - - function getTasksNs() - { - if (!isset($this->_tasksNs)) { - if (isset($this->_packageInfo['attribs'])) { - foreach ($this->_packageInfo['attribs'] as $name => $value) { - if ($value == 'http://pear.php.net/dtd/tasks-1.0') { - $this->_tasksNs = str_replace('xmlns:', '', $name); - break; - } - } - } - } - return $this->_tasksNs; - } - - /** - * Determine whether a task name is a valid task. Custom tasks may be defined - * using subdirectories by putting a "-" in the name, as in - * - * Note that this method will auto-load the task class file and test for the existence - * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class - * PEAR_Task_mycustom_task - * @param string - * @return boolean - */ - function getTask($task) - { - $this->getTasksNs(); - // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace - $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); - $taskfile = str_replace(' ', '/', ucwords($task)); - $task = str_replace(array(' ', '/'), '_', ucwords($task)); - if (class_exists("PEAR_Task_$task")) { - return "PEAR_Task_$task"; - } - $fp = @fopen("phar://go-pear.phar/PEAR/Task/$taskfile.php", 'r', true); - if ($fp) { - fclose($fp); - require_once 'phar://go-pear.phar/' . "PEAR/Task/$taskfile.php"; - return "PEAR_Task_$task"; - } - return false; - } - - /** - * Key-friendly array_splice - * @param tagname to splice a value in before - * @param mixed the value to splice in - * @param string the new tag name - */ - function _ksplice($array, $key, $value, $newkey) - { - $offset = array_search($key, array_keys($array)); - $after = array_slice($array, $offset); - $before = array_slice($array, 0, $offset); - $before[$newkey] = $value; - return array_merge($before, $after); - } - - /** - * @param array a list of possible keys, in the order they may occur - * @param mixed contents of the new package.xml tag - * @param string tag name - * @access private - */ - function _insertBefore($array, $keys, $contents, $newkey) - { - foreach ($keys as $key) { - if (isset($array[$key])) { - return $array = $this->_ksplice($array, $key, $contents, $newkey); - } - } - $array[$newkey] = $contents; - return $array; - } - - /** - * @param subsection of {@link $_packageInfo} - * @param array|string tag contents - * @param array format: - *
    -     * array(
    -     *   tagname => array(list of tag names that follow this one),
    -     *   childtagname => array(list of child tag names that follow this one),
    -     * )
    -     * 
    - * - * This allows construction of nested tags - * @access private - */ - function _mergeTag($manip, $contents, $order) - { - if (count($order)) { - foreach ($order as $tag => $curorder) { - if (!isset($manip[$tag])) { - // ensure that the tag is set up - $manip = $this->_insertBefore($manip, $curorder, array(), $tag); - } - if (count($order) > 1) { - $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); - return $manip; - } - } - } else { - return $manip; - } - if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { - $manip[$tag][] = $contents; - } else { - if (!count($manip[$tag])) { - $manip[$tag] = $contents; - } else { - $manip[$tag] = array($manip[$tag]); - $manip[$tag][] = $contents; - } - } - return $manip; - } -} -?> - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validator.php 277885 2009-03-27 19:29:31Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a8 - */ -/** - * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its - * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a8 - * @access private - */ -class PEAR_PackageFile_v2_Validator -{ - /** - * @var array - */ - var $_packageInfo; - /** - * @var PEAR_PackageFile_v2 - */ - var $_pf; - /** - * @var PEAR_ErrorStack - */ - var $_stack; - /** - * @var int - */ - var $_isValid = 0; - /** - * @var int - */ - var $_filesValid = 0; - /** - * @var int - */ - var $_curState = 0; - /** - * @param PEAR_PackageFile_v2 - * @param int - */ - function validate(&$pf, $state = PEAR_VALIDATE_NORMAL) - { - $this->_pf = &$pf; - $this->_curState = $state; - $this->_packageInfo = $this->_pf->getArray(); - $this->_isValid = $this->_pf->_isValid; - $this->_filesValid = $this->_pf->_filesValid; - $this->_stack = &$pf->_stack; - $this->_stack->getErrors(true); - if (($this->_isValid & $state) == $state) { - return true; - } - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { - return false; - } - if (!isset($this->_packageInfo['attribs']['version']) || - ($this->_packageInfo['attribs']['version'] != '2.0' && - $this->_packageInfo['attribs']['version'] != '2.1') - ) { - $this->_noPackageVersion(); - } - $structure = - array( - 'name', - 'channel|uri', - '*extends', // can't be multiple, but this works fine - 'summary', - 'description', - '+lead', // these all need content checks - '*developer', - '*contributor', - '*helper', - 'date', - '*time', - 'version', - 'stability', - 'license->?uri->?filesource', - 'notes', - 'contents', //special validation needed - '*compatible', - 'dependencies', //special validation needed - '*usesrole', - '*usestask', // reserve these for 1.4.0a1 to implement - // this will allow a package.xml to gracefully say it - // needs a certain package installed in order to implement a role or task - '*providesextension', - '*srcpackage|*srcuri', - '+phprelease|+extsrcrelease|+extbinrelease|' . - '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed - '*changelog', - ); - $test = $this->_packageInfo; - if (isset($test['dependencies']) && - isset($test['dependencies']['required']) && - isset($test['dependencies']['required']['pearinstaller']) && - isset($test['dependencies']['required']['pearinstaller']['min']) && - version_compare('1.9.0', - $test['dependencies']['required']['pearinstaller']['min'], '<') - ) { - $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']); - return false; - } - // ignore post-installation array fields - if (array_key_exists('filelist', $test)) { - unset($test['filelist']); - } - if (array_key_exists('_lastmodified', $test)) { - unset($test['_lastmodified']); - } - if (array_key_exists('#binarypackage', $test)) { - unset($test['#binarypackage']); - } - if (array_key_exists('old', $test)) { - unset($test['old']); - } - if (array_key_exists('_lastversion', $test)) { - unset($test['_lastversion']); - } - if (!$this->_stupidSchemaValidate($structure, $test, '')) { - return false; - } - if (empty($this->_packageInfo['name'])) { - $this->_tagCannotBeEmpty('name'); - } - $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel'; - if (empty($this->_packageInfo[$test])) { - $this->_tagCannotBeEmpty($test); - } - if (is_array($this->_packageInfo['license']) && - (!isset($this->_packageInfo['license']['_content']) || - empty($this->_packageInfo['license']['_content']))) { - $this->_tagCannotBeEmpty('license'); - } elseif (empty($this->_packageInfo['license'])) { - $this->_tagCannotBeEmpty('license'); - } - if (empty($this->_packageInfo['summary'])) { - $this->_tagCannotBeEmpty('summary'); - } - if (empty($this->_packageInfo['description'])) { - $this->_tagCannotBeEmpty('description'); - } - if (empty($this->_packageInfo['date'])) { - $this->_tagCannotBeEmpty('date'); - } - if (empty($this->_packageInfo['notes'])) { - $this->_tagCannotBeEmpty('notes'); - } - if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) { - $this->_tagCannotBeEmpty('time'); - } - if (isset($this->_packageInfo['dependencies'])) { - $this->_validateDependencies(); - } - if (isset($this->_packageInfo['compatible'])) { - $this->_validateCompatible(); - } - if (!isset($this->_packageInfo['bundle'])) { - if (empty($this->_packageInfo['contents'])) { - $this->_tagCannotBeEmpty('contents'); - } - if (!isset($this->_packageInfo['contents']['dir'])) { - $this->_filelistMustContainDir('contents'); - return false; - } - if (isset($this->_packageInfo['contents']['file'])) { - $this->_filelistCannotContainFile('contents'); - return false; - } - } - $this->_validateMaintainers(); - $this->_validateStabilityVersion(); - $fail = false; - if (array_key_exists('usesrole', $this->_packageInfo)) { - $roles = $this->_packageInfo['usesrole']; - if (!is_array($roles) || !isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if (!isset($role['role'])) { - $this->_usesroletaskMustHaveRoleTask('usesrole', 'role'); - $fail = true; - } else { - if (!isset($role['channel'])) { - if (!isset($role['uri'])) { - $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole'); - $fail = true; - } - } elseif (!isset($role['package'])) { - $this->_usesroletaskMustHavePackage($role['role'], 'usesrole'); - $fail = true; - } - } - } - } - if (array_key_exists('usestask', $this->_packageInfo)) { - $roles = $this->_packageInfo['usestask']; - if (!is_array($roles) || !isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if (!isset($role['task'])) { - $this->_usesroletaskMustHaveRoleTask('usestask', 'task'); - $fail = true; - } else { - if (!isset($role['channel'])) { - if (!isset($role['uri'])) { - $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask'); - $fail = true; - } - } elseif (!isset($role['package'])) { - $this->_usesroletaskMustHavePackage($role['task'], 'usestask'); - $fail = true; - } - } - } - } - - if ($fail) { - return false; - } - - $list = $this->_packageInfo['contents']; - if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) { - $this->_multipleToplevelDirNotAllowed(); - return $this->_isValid = 0; - } - - $this->_validateFilelist(); - $this->_validateRelease(); - if (!$this->_stack->hasErrors()) { - $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true); - if (PEAR::isError($chan)) { - $this->_unknownChannel($this->_pf->getChannel()); - } else { - $valpack = $chan->getValidationPackage(); - // for channel validator packages, always use the default PEAR validator. - // otherwise, they can't be installed or packaged - $validator = $chan->getValidationObject($this->_pf->getPackage()); - if (!$validator) { - $this->_stack->push(__FUNCTION__, 'error', - array_merge( - array('channel' => $chan->getName(), - 'package' => $this->_pf->getPackage()), - $valpack - ), - 'package "%channel%/%package%" cannot be properly validated without ' . - 'validation package "%channel%/%name%-%version%"'); - return $this->_isValid = 0; - } - $validator->setPackageFile($this->_pf); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_stack->push(__FUNCTION__, 'error', $error, - 'Channel validator error: field "%field%" - %reason%'); - } - foreach ($failures['warnings'] as $warning) { - $this->_stack->push(__FUNCTION__, 'warning', $warning, - 'Channel validator warning: field "%field%" - %reason%'); - } - } - } - - $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error'); - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) { - if ($this->_pf->getPackageType() == 'bundle') { - if ($this->_analyzeBundledPackages()) { - $this->_filesValid = $this->_pf->_filesValid = true; - } else { - $this->_pf->_isValid = $this->_isValid = 0; - } - } else { - if (!$this->_analyzePhpFiles()) { - $this->_pf->_isValid = $this->_isValid = 0; - } else { - $this->_filesValid = $this->_pf->_filesValid = true; - } - } - } - - if ($this->_isValid) { - return $this->_pf->_isValid = $this->_isValid = $state; - } - - return $this->_pf->_isValid = $this->_isValid = 0; - } - - function _stupidSchemaValidate($structure, $xml, $root) - { - if (!is_array($xml)) { - $xml = array(); - } - $keys = array_keys($xml); - reset($keys); - $key = current($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - $unfoundtags = $optionaltags = array(); - $ret = true; - $mismatch = false; - foreach ($structure as $struc) { - if ($key) { - $tag = $xml[$key]; - } - $test = $this->_processStructure($struc); - if (isset($test['choices'])) { - $loose = true; - foreach ($test['choices'] as $choice) { - if ($key == $choice['tag']) { - $key = next($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - $unfoundtags = $optionaltags = array(); - $mismatch = false; - if ($key && $key != $choice['tag'] && isset($choice['multiple'])) { - $unfoundtags[] = $choice['tag']; - $optionaltags[] = $choice['tag']; - if ($key) { - $mismatch = true; - } - } - $ret &= $this->_processAttribs($choice, $tag, $root); - continue 2; - } else { - $unfoundtags[] = $choice['tag']; - $mismatch = true; - } - if (!isset($choice['multiple']) || $choice['multiple'] != '*') { - $loose = false; - } else { - $optionaltags[] = $choice['tag']; - } - } - if (!$loose) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } - } else { - if ($key != $test['tag']) { - if (isset($test['multiple']) && $test['multiple'] != '*') { - $unfoundtags[] = $test['tag']; - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } else { - if ($key) { - $mismatch = true; - } - $unfoundtags[] = $test['tag']; - $optionaltags[] = $test['tag']; - } - if (!isset($test['multiple'])) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } - continue; - } else { - $unfoundtags = $optionaltags = array(); - $mismatch = false; - } - $key = next($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - if ($key && $key != $test['tag'] && isset($test['multiple'])) { - $unfoundtags[] = $test['tag']; - $optionaltags[] = $test['tag']; - $mismatch = true; - } - $ret &= $this->_processAttribs($test, $tag, $root); - continue; - } - } - if (!$mismatch && count($optionaltags)) { - // don't error out on any optional tags - $unfoundtags = array_diff($unfoundtags, $optionaltags); - } - if (count($unfoundtags)) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - } elseif ($key) { - // unknown tags - $this->_invalidTagOrder('*no tags allowed here*', $key, $root); - while ($key = next($keys)) { - $this->_invalidTagOrder('*no tags allowed here*', $key, $root); - } - } - return $ret; - } - - function _processAttribs($choice, $tag, $context) - { - if (isset($choice['attribs'])) { - if (!is_array($tag)) { - $tag = array($tag); - } - $tags = $tag; - if (!isset($tags[0])) { - $tags = array($tags); - } - $ret = true; - foreach ($tags as $i => $tag) { - if (!is_array($tag) || !isset($tag['attribs'])) { - foreach ($choice['attribs'] as $attrib) { - if ($attrib{0} != '?') { - $ret &= $this->_tagHasNoAttribs($choice['tag'], - $context); - continue 2; - } - } - } - foreach ($choice['attribs'] as $attrib) { - if ($attrib{0} != '?') { - if (!isset($tag['attribs'][$attrib])) { - $ret &= $this->_tagMissingAttribute($choice['tag'], - $attrib, $context); - } - } - } - } - return $ret; - } - return true; - } - - function _processStructure($key) - { - $ret = array(); - if (count($pieces = explode('|', $key)) > 1) { - $ret['choices'] = array(); - foreach ($pieces as $piece) { - $ret['choices'][] = $this->_processStructure($piece); - } - return $ret; - } - $multi = $key{0}; - if ($multi == '+' || $multi == '*') { - $ret['multiple'] = $key{0}; - $key = substr($key, 1); - } - if (count($attrs = explode('->', $key)) > 1) { - $ret['tag'] = array_shift($attrs); - $ret['attribs'] = $attrs; - } else { - $ret['tag'] = $key; - } - return $ret; - } - - function _validateStabilityVersion() - { - $structure = array('release', 'api'); - $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], ''); - $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], ''); - if ($a) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $this->_packageInfo['version']['release'])) { - $this->_invalidVersion('release', $this->_packageInfo['version']['release']); - } - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $this->_packageInfo['version']['api'])) { - $this->_invalidVersion('api', $this->_packageInfo['version']['api']); - } - if (!in_array($this->_packageInfo['stability']['release'], - array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) { - $this->_invalidState('release', $this->_packageInfo['stability']['release']); - } - if (!in_array($this->_packageInfo['stability']['api'], - array('devel', 'alpha', 'beta', 'stable'))) { - $this->_invalidState('api', $this->_packageInfo['stability']['api']); - } - } - } - - function _validateMaintainers() - { - $structure = - array( - 'name', - 'user', - 'email', - 'active', - ); - foreach (array('lead', 'developer', 'contributor', 'helper') as $type) { - if (!isset($this->_packageInfo[$type])) { - continue; - } - if (isset($this->_packageInfo[$type][0])) { - foreach ($this->_packageInfo[$type] as $lead) { - $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>'); - } - } else { - $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type], - '<' . $type . '>'); - } - } - } - - function _validatePhpDep($dep, $installcondition = false) - { - $structure = array( - 'min', - '*max', - '*exclude', - ); - $type = $installcondition ? '' : ''; - $this->_stupidSchemaValidate($structure, $dep, $type); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $dep['min'])) { - $this->_invalidVersion($type . '', $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $dep['max'])) { - $this->_invalidVersion($type . '', $dep['max']); - } - } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match( - '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $exclude)) { - $this->_invalidVersion($type . '', $exclude); - } - } - } - } - - function _validatePearinstallerDep($dep) - { - $structure = array( - 'min', - '*max', - '*recommended', - '*exclude', - ); - $this->_stupidSchemaValidate($structure, $dep, ''); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion('', - $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['max'])) { - $this->_invalidVersion('', - $dep['max']); - } - } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion('', - $dep['recommended']); - } - } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion('', - $exclude); - } - } - } - } - - function _validatePackageDep($dep, $group, $type = '') - { - if (isset($dep['uri'])) { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - 'uri', - 'conflicts', - '*providesextension', - ); - } else { - $structure = array( - 'name', - 'uri', - '*providesextension', - ); - } - } else { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - 'channel', - '*min', - '*max', - '*exclude', - 'conflicts', - '*providesextension', - ); - } else { - $structure = array( - 'name', - 'channel', - '*min', - '*max', - '*recommended', - '*exclude', - '*nodefault', - '*providesextension', - ); - } - } - if (isset($dep['name'])) { - $type .= '' . $dep['name'] . ''; - } - $this->_stupidSchemaValidate($structure, $dep, '' . $group . $type); - if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || - isset($dep['recommended']) || isset($dep['exclude']))) { - $this->_uriDepsCannotHaveVersioning('' . $group . $type); - } - if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') { - $this->_DepchannelCannotBeUri('' . $group . $type); - } - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion('' . $group . $type . '', $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['max'])) { - $this->_invalidVersion('' . $group . $type . '', $dep['max']); - } - } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion('' . $group . $type . '', - $dep['recommended']); - } - } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion('' . $group . $type . '', - $exclude); - } - } - } - } - - function _validateSubpackageDep($dep, $group) - { - $this->_validatePackageDep($dep, $group, ''); - if (isset($dep['providesextension'])) { - $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : ''); - } - if (isset($dep['conflicts'])) { - $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : ''); - } - } - - function _validateExtensionDep($dep, $group = false, $installcondition = false) - { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - '*min', - '*max', - '*exclude', - 'conflicts', - ); - } else { - $structure = array( - 'name', - '*min', - '*max', - '*recommended', - '*exclude', - ); - } - if ($installcondition) { - $type = ''; - } else { - $type = '' . $group . ''; - } - if (isset($dep['name'])) { - $type .= '' . $dep['name'] . ''; - } - $this->_stupidSchemaValidate($structure, $dep, $type); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '' : ''; - if ($this->_stupidSchemaValidate($structure, $dep, $type)) { - if ($dep['name'] == '*') { - if (array_key_exists('conflicts', $dep)) { - $this->_cannotConflictWithAllOs($type); - } - } - } - } - - function _validateArchDep($dep, $installcondition = false) - { - $structure = array( - 'pattern', - '*conflicts', - ); - $type = $installcondition ? '' : ''; - $this->_stupidSchemaValidate($structure, $dep, $type); - } - - function _validateInstallConditions($cond, $release) - { - $structure = array( - '*php', - '*extension', - '*os', - '*arch', - ); - if (!$this->_stupidSchemaValidate($structure, - $cond, $release)) { - return false; - } - foreach (array('php', 'extension', 'os', 'arch') as $type) { - if (isset($cond[$type])) { - $iter = $cond[$type]; - if (!is_array($iter) || !isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type == 'extension') { - $this->{"_validate{$type}Dep"}($package, false, true); - } else { - $this->{"_validate{$type}Dep"}($package, true); - } - } - } - } - } - - function _validateDependencies() - { - $structure = array( - 'required', - '*optional', - '*group->name->hint' - ); - if (!$this->_stupidSchemaValidate($structure, - $this->_packageInfo['dependencies'], '')) { - return false; - } - foreach (array('required', 'optional') as $simpledep) { - if (isset($this->_packageInfo['dependencies'][$simpledep])) { - if ($simpledep == 'optional') { - $structure = array( - '*package', - '*subpackage', - '*extension', - ); - } else { - $structure = array( - 'php', - 'pearinstaller', - '*package', - '*subpackage', - '*extension', - '*os', - '*arch', - ); - } - if ($this->_stupidSchemaValidate($structure, - $this->_packageInfo['dependencies'][$simpledep], - "<$simpledep>")) { - foreach (array('package', 'subpackage', 'extension') as $type) { - if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { - $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type != 'extension') { - if (isset($package['uri'])) { - if (isset($package['channel'])) { - $this->_UrlOrChannel($type, - $package['name']); - } - } else { - if (!isset($package['channel'])) { - $this->_NoChannel($type, $package['name']); - } - } - } - $this->{"_validate{$type}Dep"}($package, "<$simpledep>"); - } - } - } - if ($simpledep == 'optional') { - continue; - } - foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) { - if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { - $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - $this->{"_validate{$type}Dep"}($package); - } - } - } - } - } - } - if (isset($this->_packageInfo['dependencies']['group'])) { - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } - $structure = array( - '*package', - '*subpackage', - '*extension', - ); - foreach ($groups as $group) { - if ($this->_stupidSchemaValidate($structure, $group, '')) { - if (!PEAR_Validate::validGroupName($group['attribs']['name'])) { - $this->_invalidDepGroupName($group['attribs']['name']); - } - foreach (array('package', 'subpackage', 'extension') as $type) { - if (isset($group[$type])) { - $iter = $group[$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type != 'extension') { - if (isset($package['uri'])) { - if (isset($package['channel'])) { - $this->_UrlOrChannelGroup($type, - $package['name'], - $group['name']); - } - } else { - if (!isset($package['channel'])) { - $this->_NoChannelGroup($type, - $package['name'], - $group['name']); - } - } - } - $this->{"_validate{$type}Dep"}($package, ''); - } - } - } - } - } - } - } - - function _validateCompatible() - { - $compat = $this->_packageInfo['compatible']; - if (!isset($compat[0])) { - $compat = array($compat); - } - $required = array('name', 'channel', 'min', 'max', '*exclude'); - foreach ($compat as $package) { - $type = ''; - if (is_array($package) && array_key_exists('name', $package)) { - $type .= '' . $package['name'] . ''; - } - $this->_stupidSchemaValidate($required, $package, $type); - if (is_array($package) && array_key_exists('min', $package)) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $package['min'])) { - $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_NoBundledPackages(); - } - if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) { - return $this->_AtLeast2BundledPackages(); - } - foreach ($list['bundledpackage'] as $package) { - if (!is_string($package)) { - $this->_bundledPackagesMustBeFilename(); - } - } - } - - function _validateFilelist($list = false, $allowignore = false, $dirs = '') - { - $iscontents = false; - if (!$list) { - $iscontents = true; - $list = $this->_packageInfo['contents']; - if (isset($this->_packageInfo['bundle'])) { - return $this->_validateBundle($list); - } - } - if ($allowignore) { - $struc = array( - '*install->name->as', - '*ignore->name' - ); - } else { - $struc = array( - '*dir->name->?baseinstalldir', - '*file->name->role->?baseinstalldir->?md5sum' - ); - if (isset($list['dir']) && isset($list['file'])) { - // stave off validation errors without requiring a set order. - $_old = $list; - if (isset($list['attribs'])) { - $list = array('attribs' => $_old['attribs']); - } - $list['dir'] = $_old['dir']; - $list['file'] = $_old['file']; - } - } - if (!isset($list['attribs']) || !isset($list['attribs']['name'])) { - $unknown = $allowignore ? '' : ''; - $dirname = $iscontents ? '' : $unknown; - } else { - $dirname = ''; - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $list['attribs']['name']))) { - // file contains .. parent directory or . cur directory - $this->_invalidDirName($list['attribs']['name']); - } - } - $res = $this->_stupidSchemaValidate($struc, $list, $dirname); - if ($allowignore && $res) { - $ignored_or_installed = array(); - $this->_pf->getFilelist(); - $fcontents = $this->_pf->getContents(); - $filelist = array(); - if (!isset($fcontents['dir']['file'][0])) { - $fcontents['dir']['file'] = array($fcontents['dir']['file']); - } - foreach ($fcontents['dir']['file'] as $file) { - $filelist[$file['attribs']['name']] = true; - } - if (isset($list['install'])) { - if (!isset($list['install'][0])) { - $list['install'] = array($list['install']); - } - foreach ($list['install'] as $file) { - if (!isset($filelist[$file['attribs']['name']])) { - $this->_notInContents($file['attribs']['name'], 'install'); - continue; - } - if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { - $this->_multipleInstallAs($file['attribs']['name']); - } - if (!isset($ignored_or_installed[$file['attribs']['name']])) { - $ignored_or_installed[$file['attribs']['name']] = array(); - } - $ignored_or_installed[$file['attribs']['name']][] = 1; - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $file['attribs']['as']))) { - // file contains .. parent directory or . cur directory references - $this->_invalidFileInstallAs($file['attribs']['name'], - $file['attribs']['as']); - } - } - } - if (isset($list['ignore'])) { - if (!isset($list['ignore'][0])) { - $list['ignore'] = array($list['ignore']); - } - foreach ($list['ignore'] as $file) { - if (!isset($filelist[$file['attribs']['name']])) { - $this->_notInContents($file['attribs']['name'], 'ignore'); - continue; - } - if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { - $this->_ignoreAndInstallAs($file['attribs']['name']); - } - } - } - } - if (!$allowignore && isset($list['file'])) { - if (is_string($list['file'])) { - $this->_oldStyleFileNotAllowed(); - return false; - } - if (!isset($list['file'][0])) { - // single file - $list['file'] = array($list['file']); - } - foreach ($list['file'] as $i => $file) - { - if (isset($file['attribs']) && isset($file['attribs']['name'])) { - if ($file['attribs']['name']{0} == '.' && - $file['attribs']['name']{1} == '/') { - // name is something like "./doc/whatever.txt" - $this->_invalidFileName($file['attribs']['name'], $dirname); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $file['attribs']['name']))) { - // file contains .. parent directory or . cur directory - $this->_invalidFileName($file['attribs']['name'], $dirname); - } - } - if (isset($file['attribs']) && isset($file['attribs']['role'])) { - if (!$this->_validateRole($file['attribs']['role'])) { - if (isset($this->_packageInfo['usesrole'])) { - $roles = $this->_packageInfo['usesrole']; - if (!isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if ($role['role'] = $file['attribs']['role']) { - $msg = 'This package contains role "%role%" and requires ' . - 'package "%package%" to be used'; - if (isset($role['uri'])) { - $params = array('role' => $role['role'], - 'package' => $role['uri']); - } else { - $params = array('role' => $role['role'], - 'package' => $this->_pf->_registry-> - parsedPackageNameToString(array('package' => - $role['package'], 'channel' => $role['channel']), - true)); - } - $this->_stack->push('_mustInstallRole', 'error', $params, $msg); - } - } - } - $this->_invalidFileRole($file['attribs']['name'], - $dirname, $file['attribs']['role']); - } - } - if (!isset($file['attribs'])) { - continue; - } - $save = $file['attribs']; - if ($dirs) { - $save['name'] = $dirs . '/' . $save['name']; - } - unset($file['attribs']); - if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks - foreach ($file as $task => $value) { - if ($tagClass = $this->_pf->getTask($task)) { - if (!is_array($value) || !isset($value[0])) { - $value = array($value); - } - foreach ($value as $v) { - $ret = call_user_func(array($tagClass, 'validateXml'), - $this->_pf, $v, $this->_pf->_config, $save); - if (is_array($ret)) { - $this->_invalidTask($task, $ret, isset($save['name']) ? - $save['name'] : ''); - } - } - } else { - if (isset($this->_packageInfo['usestask'])) { - $roles = $this->_packageInfo['usestask']; - if (!isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if ($role['task'] = $task) { - $msg = 'This package contains task "%task%" and requires ' . - 'package "%package%" to be used'; - if (isset($role['uri'])) { - $params = array('task' => $role['task'], - 'package' => $role['uri']); - } else { - $params = array('task' => $role['task'], - 'package' => $this->_pf->_registry-> - parsedPackageNameToString(array('package' => - $role['package'], 'channel' => $role['channel']), - true)); - } - $this->_stack->push('_mustInstallTask', 'error', - $params, $msg); - } - } - } - $this->_unknownTask($task, $save['name']); - } - } - } - } - } - if (isset($list['ignore'])) { - if (!$allowignore) { - $this->_ignoreNotAllowed('ignore'); - } - } - if (isset($list['install'])) { - if (!$allowignore) { - $this->_ignoreNotAllowed('install'); - } - } - if (isset($list['file'])) { - if ($allowignore) { - $this->_fileNotAllowed('file'); - } - } - if (isset($list['dir'])) { - if ($allowignore) { - $this->_fileNotAllowed('dir'); - } else { - if (!isset($list['dir'][0])) { - $list['dir'] = array($list['dir']); - } - foreach ($list['dir'] as $dir) { - if (isset($dir['attribs']) && isset($dir['attribs']['name'])) { - if ($dir['attribs']['name'] == '/' || - !isset($this->_packageInfo['contents']['dir']['dir'])) { - // always use nothing if the filelist has already been flattened - $newdirs = ''; - } elseif ($dirs == '') { - $newdirs = $dir['attribs']['name']; - } else { - $newdirs = $dirs . '/' . $dir['attribs']['name']; - } - } else { - $newdirs = $dirs; - } - $this->_validateFilelist($dir, $allowignore, $newdirs); - } - } - } - } - - function _validateRelease() - { - if (isset($this->_packageInfo['phprelease'])) { - $release = 'phprelease'; - if (isset($this->_packageInfo['providesextension'])) { - $this->_cannotProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo['phprelease']; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, ''); - } - } - foreach (array('', 'zend') as $prefix) { - $releasetype = $prefix . 'extsrcrelease'; - if (isset($this->_packageInfo[$releasetype])) { - $release = $releasetype; - if (!isset($this->_packageInfo['providesextension'])) { - $this->_mustProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo[$releasetype]; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*configureoption->name->prompt->?default', - '*binarypackage', - '*filelist', - ), $rel, '<' . $releasetype . '>'); - if (isset($rel['binarypackage'])) { - if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) { - $rel['binarypackage'] = array($rel['binarypackage']); - } - foreach ($rel['binarypackage'] as $bin) { - if (!is_string($bin)) { - $this->_binaryPackageMustBePackagename(); - } - } - } - } - } - $releasetype = 'extbinrelease'; - if (isset($this->_packageInfo[$releasetype])) { - $release = $releasetype; - if (!isset($this->_packageInfo['providesextension'])) { - $this->_mustProvideExtension($release); - } - if (isset($this->_packageInfo['channel']) && - !isset($this->_packageInfo['srcpackage'])) { - $this->_mustSrcPackage($release); - } - if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) { - $this->_mustSrcuri($release); - } - $releases = $this->_packageInfo[$releasetype]; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, '<' . $releasetype . '>'); - } - } - } - if (isset($this->_packageInfo['bundle'])) { - $release = 'bundle'; - if (isset($this->_packageInfo['providesextension'])) { - $this->_cannotProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo['bundle']; - if (!is_array($releases) || !isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, ''); - } - } - foreach ($releases as $rel) { - if (is_array($rel) && array_key_exists('installconditions', $rel)) { - $this->_validateInstallConditions($rel['installconditions'], - "<$release>"); - } - if (is_array($rel) && array_key_exists('filelist', $rel)) { - if ($rel['filelist']) { - - $this->_validateFilelist($rel['filelist'], true); - } - } - } - } - - /** - * This is here to allow role extension through plugins - * @param string - */ - function _validateRole($role) - { - return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())); - } - - function _pearVersionTooLow($version) - { - $this->_stack->push(__FUNCTION__, 'error', - array('version' => $version), - 'This package.xml requires PEAR version %version% to parse properly, we are ' . - 'version 1.9.0'); - } - - function _invalidTagOrder($oktags, $actual, $root) - { - $this->_stack->push(__FUNCTION__, 'error', - array('oktags' => $oktags, 'actual' => $actual, 'root' => $root), - 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"'); - } - - function _ignoreNotAllowed($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '<%type%> is not allowed inside global , only inside ' . - '//, use and only'); - } - - function _fileNotAllowed($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '<%type%> is not allowed inside release , only inside ' . - ', use and only'); - } - - function _oldStyleFileNotAllowed() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Old-style name is not allowed. Use' . - ''); - } - - function _tagMissingAttribute($tag, $attr, $context) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, - 'attribute' => $attr, 'context' => $context), - 'tag <%tag%> in context "%context%" has no attribute "%attribute%"'); - } - - function _tagHasNoAttribs($tag, $context) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, - 'context' => $context), - 'tag <%tag%> has no attributes in context "%context%"'); - } - - function _invalidInternalStructure() - { - $this->_stack->push(__FUNCTION__, 'exception', array(), - 'internal array was not generated by compatible parser, or extreme parser error, cannot continue'); - } - - function _invalidFileRole($file, $dir, $role) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file, 'dir' => $dir, 'role' => $role, - 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())), - 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%'); - } - - function _invalidFileName($file, $dir) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file), - 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."'); - } - - function _invalidFileInstallAs($file, $as) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file, 'as' => $as), - 'File "%file%" cannot contain "./" or contain ".."'); - } - - function _invalidDirName($dir) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'dir' => $file), - 'Directory "%dir%" cannot begin with "./" or contain ".."'); - } - - function _filelistCannotContainFile($filelist) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), - '<%tag%> can only contain , contains . Use ' . - ' as the first dir element'); - } - - function _filelistMustContainDir($filelist) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), - '<%tag%> must contain . Use as the ' . - 'first dir element'); - } - - function _tagCannotBeEmpty($tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), - '<%tag%> cannot be empty (<%tag%/>)'); - } - - function _UrlOrChannel($type, $name) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name), - 'Required dependency <%type%> "%name%" can have either url OR ' . - 'channel attributes, and not both'); - } - - function _NoChannel($type, $name) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name), - 'Required dependency <%type%> "%name%" must have either url OR ' . - 'channel attributes'); - } - - function _UrlOrChannelGroup($type, $name, $group) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name, 'group' => $group), - 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' . - 'channel attributes, and not both'); - } - - function _NoChannelGroup($type, $name, $group) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name, 'group' => $group), - 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' . - 'channel attributes'); - } - - function _unknownChannel($channel) - { - $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel), - 'Unknown channel "%channel%"'); - } - - function _noPackageVersion() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'package.xml tag has no version attribute, or version is not 2.0'); - } - - function _NoBundledPackages() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'No tag was found in , required for bundle packages'); - } - - function _AtLeast2BundledPackages() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'At least 2 packages must be bundled in a bundle package'); - } - - function _ChannelOrUri($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Bundled package "%name%" can have either a uri or a channel, not both'); - } - - function _noChildTag($child, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag), - 'Tag <%tag%> is missing child tag <%child%>'); - } - - function _invalidVersion($type, $value) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value), - 'Version type <%type%> is not a valid version (%value%)'); - } - - function _invalidState($type, $value) - { - $states = array('stable', 'beta', 'alpha', 'devel'); - if ($type != 'api') { - $states[] = 'snapshot'; - } - if (strtolower($value) == 'rc') { - $this->_stack->push(__FUNCTION__, 'error', - array('version' => $this->_packageInfo['version']['release']), - 'RC is not a state, it is a version postfix, try %version%RC1, stability beta'); - } - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value, - 'types' => $states), - 'Stability type <%type%> is not a valid stability (%value%), must be one of ' . - '%types%'); - } - - function _invalidTask($task, $ret, $file) - { - switch ($ret[0]) { - case PEAR_TASK_ERROR_MISSING_ATTRIB : - $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%'; - break; - case PEAR_TASK_ERROR_NOATTRIBS : - $info = array('task' => $task, 'file' => $file); - $msg = 'task <%task%> has no attributes in file %file%'; - break; - case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE : - $info = array('attrib' => $ret[1], 'values' => $ret[3], - 'was' => $ret[2], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '. - 'in file %file%, expecting one of "%values%"'; - break; - case PEAR_TASK_ERROR_INVALID : - $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> in file %file% is invalid because of "%reason%"'; - break; - } - $this->_stack->push(__FUNCTION__, 'error', $info, $msg); - } - - function _unknownTask($task, $file) - { - $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file), - 'Unknown task "%task%" passed in file '); - } - - function _subpackageCannotProvideExtension($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Subpackage dependency "%name%" cannot use , ' . - 'only package dependencies can use this tag'); - } - - function _subpackagesCannotConflict($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Subpackage dependency "%name%" cannot use , ' . - 'only package dependencies can use this tag'); - } - - function _cannotProvideExtension($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages cannot use , only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension'); - } - - function _mustProvideExtension($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages must use to indicate which PHP extension is provided'); - } - - function _cannotHaveSrcpackage($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages cannot specify a source code package, only extension binaries may use the tag'); - } - - function _mustSrcPackage($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '/ packages must specify a source code package with '); - } - - function _mustSrcuri($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '/ packages must specify a source code package with '); - } - - function _uriDepsCannotHaveVersioning($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: dependencies with a tag cannot have any versioning information'); - } - - function _conflictingDepsCannotHaveVersioning($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: conflicting dependencies cannot have versioning info, use to ' . - 'exclude specific versions of a dependency'); - } - - function _DepchannelCannotBeUri($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' . - 'dependencies only'); - } - - function _bundledPackagesMustBeFilename() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - ' tags must contain only the filename of a package release ' . - 'in the bundle'); - } - - function _binaryPackageMustBePackagename() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - ' tags must contain the name of a package that is ' . - 'a compiled version of this extsrc/zendextsrc package'); - } - - function _fileNotFound($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'File "%file%" in package.xml does not exist'); - } - - function _notInContents($file, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag), - '<%tag% name="%file%"> is invalid, file is not in '); - } - - function _cannotValidateNoPathSet() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Cannot validate files, no path to package file is set (use setPackageFile())'); - } - - function _usesroletaskMustHaveChannelOrUri($role, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), - '<%tag%> for role "%role%" must contain either , or and '); - } - - function _usesroletaskMustHavePackage($role, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), - '<%tag%> for role "%role%" must contain '); - } - - function _usesroletaskMustHaveRoleTask($tag, $type) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type), - '<%tag%> must contain <%type%> defining the %type% to be used'); - } - - function _cannotConflictWithAllOs($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), - '%tag% cannot conflict with all OSes'); - } - - function _invalidDepGroupName($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Invalid dependency group name "%name%"'); - } - - function _multipleToplevelDirNotAllowed() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Multiple top-level tags are not allowed. Enclose them ' . - 'in a '); - } - - function _multipleInstallAs($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Only one tag is allowed for file "%file%"'); - } - - function _ignoreAndInstallAs($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Cannot have both and tags for file "%file%"'); - } - - function _analyzeBundledPackages() - { - if (!$this->_isValid) { - return false; - } - if (!$this->_pf->getPackageType() == 'bundle') { - return false; - } - if (!isset($this->_pf->_packageFile)) { - return false; - } - $dir_prefix = dirname($this->_pf->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : - array($common, 'log'); - $info = $this->_pf->getContents(); - $info = $info['bundledpackage']; - if (!is_array($info)) { - $info = array($info); - } - $pkg = &new PEAR_PackageFile($this->_pf->_config); - foreach ($info as $package) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) { - $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package); - $this->_isValid = 0; - continue; - } - call_user_func_array($log, array(1, "Analyzing bundled package $package")); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package, - PEAR_VALIDATE_NORMAL); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - call_user_func_array($log, array(0, "ERROR: package $package is not a valid " . - 'package')); - $inf = $ret->getUserInfo(); - if (is_array($inf)) { - foreach ($inf as $err) { - call_user_func_array($log, array(1, $err['message'])); - } - } - return false; - } - } - return true; - } - - function _analyzePhpFiles() - { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_pf->_packageFile)) { - $this->_cannotValidateNoPathSet(); - return false; - } - $dir_prefix = dirname($this->_pf->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : - array(&$common, 'log'); - $info = $this->_pf->getContents(); - if (!$info || !isset($info['dir']['file'])) { - $this->_tagCannotBeEmpty('contents>_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); - $this->_isValid = 0; - continue; - } - if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); - } - } - } - $this->_packageName = $pn = $this->_pf->getPackage(); - $pnl = strlen($pn); - foreach ($provides as $key => $what) { - if (isset($what['explicit']) || !$what) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), - 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), - 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); - } - } - return $this->_isValid; - } - - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @param boolean whether to analyze $file as the file contents - * @return mixed - */ - function analyzeSourceCode($file, $string = false) - { - if (!function_exists("token_get_all")) { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer'); - return false; - } - - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); - } - - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); - } - - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); - } - - if ($string) { - $contents = $file; - } else { - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); - } - - // Silence this function so we can catch PHP Warnings and show our own custom message - $tokens = @token_get_all($contents); - if (isset($php_errormsg)) { - if (isset($this->_stack)) { - $pn = $this->_pf->getPackage(); - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'package' => $pn), - 'in %file%: Could not process file for unkown reasons,' . - ' possibly a PHP parse error in %file% from %package%'); - } - } -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); - } - } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; - } - - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; - } - } - - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Parser error: invalid PHP found in file "%file%"'); - } else { - PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", - PEAR_COMMON_ERROR_INVALIDPHP); - } - - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - ) - ) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'warning', array( - 'file' => $file), - 'Error, PHP5 token encountered in %file%,' . - ' analysis should be in PHP5'); - } else { - PEAR::raiseError('Error: PHP5 token encountered in ' . $file . - 'packaging should be done in PHP 5'); - return false; - } - } - } - - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } - - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; - } - - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } - } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file), - 'Parser error: invalid PHP found in file "%file%"'); - } else { - PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", - PEAR_COMMON_ERROR_INVALIDPHP); - } - - return false; - } - - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; - } - - continue 2; - } - } - - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * - */ - function _buildProvidesArray($srcinfo) - { - if (!$this->_isValid) { - return array(); - } - - $providesret = array(); - $file = basename($srcinfo['source_file']); - $pn = isset($this->_pf) ? $this->_pf->getPackage() : ''; - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($providesret[$key])) { - continue; - } - - $providesret[$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $providesret[$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($providesret[$key])) { - continue; - } - - $providesret[$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($providesret[$key])) { - continue; - } - - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - - $providesret[$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - - return $providesret; - } -} - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Registry.php 287555 2009-08-21 21:27:27Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * for PEAR_Error - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/DependencyDB.php'; - -define('PEAR_REGISTRY_ERROR_LOCK', -2); -define('PEAR_REGISTRY_ERROR_FORMAT', -3); -define('PEAR_REGISTRY_ERROR_FILE', -4); -define('PEAR_REGISTRY_ERROR_CONFLICT', -5); -define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); - -/** - * Administration class used to maintain the installed package database. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Registry extends PEAR -{ - /** - * File containing all channel information. - * @var string - */ - var $channels = ''; - - /** Directory where registry files are stored. - * @var string - */ - var $statedir = ''; - - /** File where the file map is stored - * @var string - */ - var $filemap = ''; - - /** Directory where registry files for channels are stored. - * @var string - */ - var $channelsdir = ''; - - /** Name of file used for locking the registry - * @var string - */ - var $lockfile = ''; - - /** File descriptor used during locking - * @var resource - */ - var $lock_fp = null; - - /** Mode used during locking - * @var int - */ - var $lock_mode = 0; // XXX UNUSED - - /** Cache of package information. Structure: - * array( - * 'package' => array('id' => ... ), - * ... ) - * @var array - */ - var $pkginfo_cache = array(); - - /** Cache of file map. Structure: - * array( '/path/to/file' => 'package', ... ) - * @var array - */ - var $filemap_cache = array(); - - /** - * @var false|PEAR_ChannelFile - */ - var $_pearChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_peclChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_docChannel; - - /** - * @var PEAR_DependencyDB - */ - var $_dependencyDB; - - /** - * @var PEAR_Config - */ - var $_config; - - /** - * PEAR_Registry constructor. - * - * @param string (optional) PEAR install directory (for .php files) - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * - * @access public - */ - function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, - $pecl_channel = false) - { - parent::PEAR(); - $this->setInstallDir($pear_install_dir); - $this->_pearChannel = $pear_channel; - $this->_peclChannel = $pecl_channel; - $this->_config = false; - } - - function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) - { - $ds = DIRECTORY_SEPARATOR; - $this->install_dir = $pear_install_dir; - $this->channelsdir = $pear_install_dir.$ds.'.channels'; - $this->statedir = $pear_install_dir.$ds.'.registry'; - $this->filemap = $pear_install_dir.$ds.'.filemap'; - $this->lockfile = $pear_install_dir.$ds.'.lock'; - } - - function hasWriteAccess() - { - if (!file_exists($this->install_dir)) { - $dir = $this->install_dir; - while ($dir && $dir != '.') { - $olddir = $dir; - $dir = dirname($dir); - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - - if ($dir == $olddir) { // this can happen in safe mode - return @is_writable($dir); - } - } - - return false; - } - - return is_writeable($this->install_dir); - } - - function setConfig(&$config, $resetInstallDir = true) - { - $this->_config = &$config; - if ($resetInstallDir) { - $this->setInstallDir($config->get('php_dir')); - } - } - - function _initializeChannelDirs() - { - static $running = false; - if (!$running) { - $running = true; - $ds = DIRECTORY_SEPARATOR; - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $pear_channel = $this->_pearChannel; - if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setAlias('pear'); - $pear_channel->setServer('pear.php.net'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); - //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/'); - } else { - $pear_channel->setServer('pear.php.net'); - $pear_channel->setAlias('pear'); - } - - $pear_channel->validate(); - $this->_addChannel($pear_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { - $pecl_channel = $this->_peclChannel; - if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $pecl_channel = new PEAR_ChannelFile; - $pecl_channel->setAlias('pecl'); - $pecl_channel->setServer('pecl.php.net'); - $pecl_channel->setSummary('PHP Extension Community Library'); - $pecl_channel->setDefaultPEARProtocols(); - $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - } else { - $pecl_channel->setServer('pecl.php.net'); - $pecl_channel->setAlias('pecl'); - } - - $pecl_channel->validate(); - $this->_addChannel($pecl_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { - $doc_channel = $this->_docChannel; - if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setAlias('phpdocs'); - $doc_channel->setServer('doc.php.net'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); - } else { - $doc_channel->setServer('doc.php.net'); - $doc_channel->setAlias('doc'); - } - - $doc_channel->validate(); - $this->_addChannel($doc_channel); - } - - if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - $this->_addChannel($private); - } - $this->_rebuildFileMap(); - } - - $running = false; - } - } - - function _initializeDirs() - { - $ds = DIRECTORY_SEPARATOR; - // XXX Compatibility code should be removed in the future - // rename all registry files if any to lowercase - if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && - $handle = opendir($this->statedir)) { - $dest = $this->statedir . $ds; - while (false !== ($file = readdir($handle))) { - if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { - rename($dest . $file, $dest . strtolower($file)); - } - } - closedir($handle); - } - - $this->_initializeChannelDirs(); - if (!file_exists($this->filemap)) { - $this->_rebuildFileMap(); - } - $this->_initializeDepDB(); - } - - function _initializeDepDB() - { - if (!isset($this->_dependencyDB)) { - static $initializing = false; - if (!$initializing) { - $initializing = true; - if (!$this->_config) { // never used? - $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; - $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . - $file); - $this->_config->setRegistry($this); - $this->_config->set('php_dir', $this->install_dir); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - // attempt to recover by removing the dep db - if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb')) { - @unlink($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - echo $this->_dependencyDB->getMessage(); - echo 'Unrecoverable error'; - exit(1); - } - } - - $initializing = false; - } - } - } - - /** - * PEAR_Registry destructor. Makes sure no locks are forgotten. - * - * @access private - */ - function _PEAR_Registry() - { - parent::_PEAR(); - if (is_resource($this->lock_fp)) { - $this->_unlock(); - } - } - - /** - * Make sure the directory where we keep registry files exists. - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertStateDir($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_assertChannelStateDir($channel); - } - - static $init = false; - if (!file_exists($this->statedir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://go-pear.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $this->statedir))) { - return $this->raiseError("could not create directory '{$this->statedir}'"); - } - $init = true; - } elseif (!is_dir($this->statedir)) { - return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . - 'it already exists and is not a directory'); - } - - $ds = DIRECTORY_SEPARATOR; - if (!file_exists($this->channelsdir)) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - $init = true; - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . - 'it already exists and is not a directory'); - } - - if ($init) { - static $running = false; - if (!$running) { - $running = true; - $this->_initializeDirs(); - $running = false; - $init = false; - } - } else { - $this->_initializeDepDB(); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files exists for a non-standard channel. - * - * @param string channel name - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelStateDir($channel) - { - $ds = DIRECTORY_SEPARATOR; - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - return $this->_assertStateDir($channel); - } - - $channelDir = $this->_channelDirectoryName($channel); - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - - if (!file_exists($channelDir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://go-pear.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $channelDir))) { - return $this->raiseError("could not create directory '" . $channelDir . - "'"); - } - } elseif (!is_dir($channelDir)) { - return $this->raiseError("could not create directory '" . $channelDir . - "', already exists and is not a directory"); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files for channels exists - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelDir() - { - if (!file_exists($this->channelsdir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://go-pear.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir))) { - return $this->raiseError("could not create directory '{$this->channelsdir}'"); - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "', it already exists and is not a directory"); - } - - if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://go-pear.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { - return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); - } - } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "/.alias', it already exists and is not a directory"); - } - - return true; - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _packageFileName($package, $channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . - strtolower($package) . '.reg'; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; - } - - /** - * Get the name of the file where data for a given channel is stored. - * @param string channel name - * @return string registry file name - */ - function _channelFileName($channel, $noaliases = false) - { - if (!$noaliases) { - if (file_exists($this->_getChannelAliasFileName($channel))) { - $channel = implode('', file($this->_getChannelAliasFileName($channel))); - } - } - return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', - strtolower($channel)) . '.reg'; - } - - /** - * @param string - * @return string - */ - function _getChannelAliasFileName($alias) - { - return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . - DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; - } - - /** - * Get the name of a channel from its alias - */ - function _getChannelFromAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear.php.net'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl.php.net'; - } - - if ($channel == 'doc.php.net') { - return 'doc.php.net'; - } - - if ($channel == '__uri') { - return '__uri'; - } - - return false; - } - - $channel = strtolower($channel); - if (file_exists($this->_getChannelAliasFileName($channel))) { - // translate an alias to an actual channel - return implode('', file($this->_getChannelAliasFileName($channel))); - } - - return $channel; - } - - /** - * Get the alias of a channel from its alias or its name - */ - function _getAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl'; - } - - if ($channel == 'doc.php.net') { - return 'phpdocs'; - } - - return false; - } - - $channel = $this->_getChannel($channel); - if (PEAR::isError($channel)) { - return $channel; - } - - return $channel->getAlias(); - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _channelDirectoryName($channel) - { - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return $this->statedir; - } - - $ch = $this->_getChannelFromAlias($channel); - if (!$ch) { - $ch = $channel; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . - str_replace('/', '_', $ch)); - } - - function _openPackageFile($package, $mode, $channel = false) - { - if (!$this->_assertStateDir($channel)) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_packageFileName($package, $channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closePackageFile($fp) - { - fclose($fp); - } - - function _openChannelFile($channel, $mode) - { - if (!$this->_assertChannelDir()) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_channelFileName($channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closeChannelFile($fp) - { - fclose($fp); - } - - function _rebuildFileMap() - { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php'; - } - - $channels = $this->_listAllPackages(); - $files = array(); - foreach ($channels as $channel => $packages) { - foreach ($packages as $package) { - $version = $this->_packageInfo($package, 'version', $channel); - $filelist = $this->_packageInfo($package, 'filelist', $channel); - if (!is_array($filelist)) { - continue; - } - - foreach ($filelist as $name => $attrs) { - if (isset($attrs['attribs'])) { - $attrs = $attrs['attribs']; - } - - // it is possible for conflicting packages in different channels to - // conflict with data files/doc files - if ($name == 'dirtree') { - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = $package; - } - - if (isset($attrs['baseinstalldir'])) { - $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; - } else { - $file = $name; - } - - $file = preg_replace(',^/+,', '', $file); - if ($channel != 'pear.php.net') { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = array(strtolower($channel), - strtolower($package)); - } else { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = strtolower($package); - } - } - } - } - - - $this->_assertStateDir(); - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->filemap, 'wb'); - if (!$fp) { - return false; - } - - $this->filemap_cache = $files; - fwrite($fp, serialize($files)); - fclose($fp); - return true; - } - - function _readFileMap() - { - if (!file_exists($this->filemap)) { - return array(); - } - - $fp = @fopen($this->filemap, 'r'); - if (!$fp) { - return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); - } - - clearstatcache(); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - $fsize = filesize($this->filemap); - fclose($fp); - $data = file_get_contents($this->filemap); - set_magic_quotes_runtime($rt); - $tmp = unserialize($data); - if (!$tmp && $fsize > 7) { - return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); - } - - $this->filemap_cache = $tmp; - return true; - } - - /** - * Lock the registry. - * - * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. - * See flock manual for more information. - * - * @return bool TRUE on success, FALSE if locking failed, or a - * PEAR error if some other error occurs (such as the - * lock file not being writable). - * - * @access private - */ - function _lock($mode = LOCK_EX) - { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->lock_fp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - if (!$this->_assertStateDir()) { - if ($mode == LOCK_EX) { - return $this->raiseError('Registry directory is not writeable by the current user'); - } - - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH || $mode === LOCK_UN) { - if (!file_exists($this->lockfile)) { - touch($this->lockfile); - } - $open_mode = 'r'; - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = @fopen($this->lockfile, $open_mode); - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = null; - return $this->raiseError("could not create lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->lock_fp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - //is resource at this point, close it on error. - fclose($this->lock_fp); - $this->lock_fp = null; - return $this->raiseError("could not acquire $str lock ($this->lockfile)", - PEAR_REGISTRY_ERROR_LOCK); - } - - return true; - } - - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->lock_fp)) { - fclose($this->lock_fp); - } - - $this->lock_fp = null; - return $ret; - } - - function _packageExists($package, $channel = false) - { - return file_exists($this->_packageFileName($package, $channel)); - } - - /** - * Determine whether a channel exists in the registry - * - * @param string Channel name - * @param bool if true, then aliases will be ignored - * @return boolean - */ - function _channelExists($channel, $noaliases = false) - { - $a = file_exists($this->_channelFileName($channel, $noaliases)); - if (!$a && $channel == 'pear.php.net') { - return true; - } - - if (!$a && $channel == 'pecl.php.net') { - return true; - } - - if (!$a && $channel == 'doc.php.net') { - return true; - } - - return $a; - } - - /** - * Determine whether a mirror exists within the deafult channel in the registry - * - * @param string Channel name - * @param string Mirror name - * - * @return boolean - */ - function _mirrorExists($channel, $mirror) - { - $data = $this->_channelInfo($channel); - if (!isset($data['servers']['mirror'])) { - return false; - } - - foreach ($data['servers']['mirror'] as $m) { - if ($m['attribs']['host'] == $mirror) { - return true; - } - } - - return false; - } - - /** - * @param PEAR_ChannelFile Channel object - * @param donotuse - * @param string Last-Modified HTTP tag from remote request - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function _addChannel($channel, $update = false, $lastmodified = false) - { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - - if (file_exists($this->_channelFileName($channel->getName()))) { - if (!$update) { - return false; - } - - $checker = $this->_getChannel($channel->getName()); - if (PEAR::isError($checker)) { - return $checker; - } - - if ($channel->getAlias() != $checker->getAlias()) { - if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { - @unlink($this->_getChannelAliasFileName($checker->getAlias())); - } - } - } else { - if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { - return false; - } - } - - $ret = $this->_assertChannelDir(); - if (PEAR::isError($ret)) { - return $ret; - } - - $ret = $this->_assertChannelStateDir($channel->getName()); - if (PEAR::isError($ret)) { - return $ret; - } - - if ($channel->getAlias() != $channel->getName()) { - if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && - $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { - $channel->setAlias($channel->getName()); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); - if (!$fp) { - return false; - } - - fwrite($fp, $channel->getName()); - fclose($fp); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); - if (!$fp) { - return false; - } - - $info = $channel->toArray(); - if ($lastmodified) { - $info['_lastmodified'] = $lastmodified; - } else { - $info['_lastmodified'] = date('r'); - } - - fwrite($fp, serialize($info)); - fclose($fp); - return true; - } - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function _deleteChannel($channel) - { - if (!is_string($channel)) { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - $channel = $channel->getName(); - } - - if ($this->_getChannelFromAlias($channel) == '__uri') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - return false; - } - - if (!$this->_channelExists($channel)) { - return false; - } - - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return false; - } - - $channel = $this->_getChannelFromAlias($channel); - if ($channel == 'pear.php.net') { - return false; - } - - $test = $this->_listChannelPackages($channel); - if (count($test)) { - return false; - } - - $test = @rmdir($this->_channelDirectoryName($channel)); - if (!$test) { - return false; - } - - $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); - if (file_exists($file)) { - $test = @unlink($file); - if (!$test) { - return false; - } - } - - $file = $this->_channelFileName($channel); - $ret = true; - if (file_exists($file)) { - $ret = @unlink($file); - } - - return $ret; - } - - /** - * Determine whether a channel exists in the registry - * @param string Channel Alias - * @return boolean - */ - function _isChannelAlias($alias) - { - return file_exists($this->_getChannelAliasFileName($alias)); - } - - /** - * @param string|null - * @param string|null - * @param string|null - * @return array|null - * @access private - */ - function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if ($package === null) { - if ($channel === null) { - $channels = $this->_listChannels(); - $ret = array(); - foreach ($channels as $channel) { - $channel = strtolower($channel); - $ret[$channel] = array(); - $packages = $this->_listPackages($channel); - foreach ($packages as $package) { - $ret[$channel][] = $this->_packageInfo($package, null, $channel); - } - } - - return $ret; - } - - $ps = $this->_listPackages($channel); - if (!count($ps)) { - return array(); - } - return array_map(array(&$this, '_packageInfo'), - $ps, array_fill(0, count($ps), null), - array_fill(0, count($ps), $channel)); - } - - $fp = $this->_openPackageFile($package, 'r', $channel); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closePackageFile($fp); - $data = file_get_contents($this->_packageFileName($package, $channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - if ($key === null) { - return $data; - } - - // compatibility for package.xml version 2.0 - if (isset($data['old'][$key])) { - return $data['old'][$key]; - } - - if (isset($data[$key])) { - return $data[$key]; - } - - return null; - } - - /** - * @param string Channel name - * @param bool whether to strictly retrieve info of channels, not just aliases - * @return array|null - */ - function _channelInfo($channel, $noaliases = false) - { - if (!$this->_channelExists($channel, $noaliases)) { - return null; - } - - $fp = $this->_openChannelFile($channel, 'r'); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closeChannelFile($fp); - $data = file_get_contents($this->_channelFileName($channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - return $data; - } - - function _listChannels() - { - $channellist = array(); - if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { - return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); - } - - $dp = opendir($this->channelsdir); - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - if ($ent == '__uri.reg') { - $channellist[] = '__uri'; - continue; - } - - $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); - } - - closedir($dp); - if (!in_array('pear.php.net', $channellist)) { - $channellist[] = 'pear.php.net'; - } - - if (!in_array('pecl.php.net', $channellist)) { - $channellist[] = 'pecl.php.net'; - } - - if (!in_array('doc.php.net', $channellist)) { - $channellist[] = 'doc.php.net'; - } - - - if (!in_array('__uri', $channellist)) { - $channellist[] = '__uri'; - } - - natsort($channellist); - return $channellist; - } - - function _listPackages($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_listChannelPackages($channel); - } - - if (!file_exists($this->statedir) || !is_dir($this->statedir)) { - return array(); - } - - $pkglist = array(); - $dp = opendir($this->statedir); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - $pkglist[] = substr($ent, 0, -4); - } - closedir($dp); - return $pkglist; - } - - function _listChannelPackages($channel) - { - $pkglist = array(); - if (!file_exists($this->_channelDirectoryName($channel)) || - !is_dir($this->_channelDirectoryName($channel))) { - return array(); - } - - $dp = opendir($this->_channelDirectoryName($channel)); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - $pkglist[] = substr($ent, 0, -4); - } - - closedir($dp); - return $pkglist; - } - - function _listAllPackages() - { - $ret = array(); - foreach ($this->_listChannels() as $channel) { - $ret[$channel] = $this->_listPackages($channel); - } - - return $ret; - } - - /** - * Add an installed package to the registry - * @param string package name - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - * @access private - */ - function _addPackage($package, $info) - { - if ($this->_packageExists($package)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb'); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($info['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _addPackage2($info) - { - if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { - return false; - } - - if (!$info->validate()) { - if (class_exists('PEAR_Common')) { - $ui = PEAR_Frontend::singleton(); - if ($ui) { - foreach ($info->getValidationWarnings() as $err) { - $ui->log($err['message'], true); - } - } - } - return false; - } - - $channel = $info->getChannel(); - $package = $info->getPackage(); - $save = $info; - if ($this->_packageExists($package, $channel)) { - return false; - } - - if (!$this->_channelExists($channel, true)) { - return false; - } - - $info = $info->toArray(true); - if (!$info) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb', $channel); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param array parsed package.xml 1.0 - * @param bool this parameter is only here for BC. Don't use it. - * @access private - */ - function _updatePackage($package, $info, $merge = true) - { - $oldinfo = $this->_packageInfo($package); - if (empty($oldinfo)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'w'); - if ($fp === null) { - return false; - } - - if (is_object($info)) { - $info = $info->toArray(); - } - $info['_lastmodified'] = time(); - - $newinfo = $info; - if ($merge) { - $info = array_merge($oldinfo, $info); - } else { - $diff = $info; - } - - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($newinfo['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _updatePackage2($info) - { - if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { - return false; - } - - $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); - if ($fp === null) { - return false; - } - - $save = $info; - $info = $save->getArray(true); - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param string Channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - * @access private - */ - function &_getPackage($package, $channel = 'pear.php.net') - { - $info = $this->_packageInfo($package, null, $channel); - if ($info === null) { - return $info; - } - - $a = $this->_config; - if (!$a) { - $this->_config = &new PEAR_Config; - $this->_config->set('php_dir', $this->statedir); - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php'; - } - - $pkg = &new PEAR_PackageFile($this->_config); - $pf = &$pkg->fromArray($info); - return $pf; - } - - /** - * @param string channel name - * @param bool whether to strictly retrieve channel names - * @return PEAR_ChannelFile|PEAR_Error - * @access private - */ - function &_getChannel($channel, $noaliases = false) - { - $ch = false; - if ($this->_channelExists($channel, $noaliases)) { - $chinfo = $this->_channelInfo($channel, $noaliases); - if ($chinfo) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); - } - } - - if ($ch) { - if ($ch->validate()) { - return $ch; - } - - foreach ($ch->getErrors(true) as $err) { - $message = $err['message'] . "\n"; - } - - $ch = PEAR::raiseError($message); - return $ch; - } - - if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setServer('pear.php.net'); - $pear_channel->setAlias('pear'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setServer('pecl.php.net'); - $pear_channel->setAlias('pecl'); - $pear_channel->setSummary('PHP Extension Community Library'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setServer('doc.php.net'); - $doc_channel->setAlias('phpdocs'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); - $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); - return $doc_channel; - } - - - if ($this->_getChannelFromAlias($channel) == '__uri') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - return $private; - } - - return $ch; - } - - /** - * @param string Package name - * @param string Channel name - * @return bool - */ - function packageExists($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageExists($package, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - - // {{{ channelExists() - - /** - * @param string channel name - * @param bool if true, then aliases will be ignored - * @return bool - */ - function channelExists($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelExists($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - /** - * @param string channel name mirror is in - * @param string mirror name - * - * @return bool - */ - function mirrorExists($channel, $mirror) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - - $ret = $this->_mirrorExists($channel, $mirror); - $this->_unlock(); - return $ret; - } - - // {{{ isAlias() - - /** - * Determines whether the parameter is an alias of a channel - * @param string - * @return bool - */ - function isAlias($alias) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_isChannelAlias($alias); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ packageInfo() - - /** - * @param string|null - * @param string|null - * @param string - * @return array|null - */ - function packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageInfo($package, $key, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ channelInfo() - - /** - * Retrieve a raw array of channel data. - * - * Do not use this, instead use {@link getChannel()} for normal - * operations. Array structure is undefined in this method - * @param string channel name - * @param bool whether to strictly retrieve information only on non-aliases - * @return array|null|PEAR_Error - */ - function channelInfo($channel = null, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelInfo($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - /** - * @param string - */ - function channelName($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getChannelFromAlias($channel); - $this->_unlock(); - return $ret; - } - - /** - * @param string - */ - function channelAlias($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getAlias($channel); - $this->_unlock(); - return $ret; - } - // {{{ listPackages() - - function listPackages($channel = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listPackages($channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listAllPackages() - - function listAllPackages() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listAllPackages(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listChannel() - - function listChannels() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listChannels(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ addPackage() - - /** - * Add an installed package to the registry - * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object - * that will be passed to {@link addPackage2()} - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - */ - function addPackage($package, $info) - { - if (is_object($info)) { - return $this->addPackage2($info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage($package, $info); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($info); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ addPackage2() - - function addPackage2($info) - { - if (!is_object($info)) { - return $this->addPackage($info['package'], $info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - return $ret; - } - - // }}} - // {{{ updateChannel() - - /** - * For future expandibility purposes, separate this - * @param PEAR_ChannelFile - */ - function updateChannel($channel, $lastmodified = null) - { - if ($channel->getName() == '__uri') { - return false; - } - return $this->addChannel($channel, $lastmodified, true); - } - - // }}} - // {{{ deleteChannel() - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function deleteChannel($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_deleteChannel($channel); - $this->_unlock(); - if ($ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - - return $ret; - } - - // }}} - // {{{ addChannel() - - /** - * @param PEAR_ChannelFile Channel object - * @param string Last-Modified header from HTTP for caching - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function addChannel($channel, $lastmodified = false, $update = false) - { - if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) { - return false; - } - - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_addChannel($channel, $update, $lastmodified); - $this->_unlock(); - if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - - return $ret; - } - - // }}} - // {{{ deletePackage() - - function deletePackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $file = $this->_packageFileName($package, $channel); - $ret = file_exists($file) ? @unlink($file) : false; - $this->_rebuildFileMap(); - $this->_unlock(); - $p = array('channel' => $channel, 'package' => $package); - $this->_dependencyDB->uninstallPackage($p); - return $ret; - } - - // }}} - // {{{ updatePackage() - - function updatePackage($package, $info, $merge = true) - { - if (is_object($info)) { - return $this->updatePackage2($info, $merge); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_updatePackage($package, $info, $merge); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($this->packageInfo($package)); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ updatePackage2() - - function updatePackage2($info) - { - - if (!is_object($info)) { - return $this->updatePackage($info['package'], $info, $merge); - } - - if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { - return false; - } - - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_updatePackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - - return $ret; - } - - // }}} - // {{{ getChannel() - /** - * @param string channel name - * @param bool whether to strictly return raw channels (no aliases) - * @return PEAR_ChannelFile|PEAR_Error - */ - function &getChannel($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = &$this->_getChannel($channel, $noaliases); - $this->_unlock(); - if (!$ret) { - return PEAR::raiseError('Unknown channel: ' . $channel); - } - return $ret; - } - - // }}} - // {{{ getPackage() - /** - * @param string package name - * @param string channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - */ - function &getPackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $pf = &$this->_getPackage($package, $channel); - $this->_unlock(); - return $pf; - } - - // }}} - - /** - * Get PEAR_PackageFile_v[1/2] objects representing the contents of - * a dependency group that are installed. - * - * This is used at uninstall-time - * @param array - * @return array|false - */ - function getInstalledGroup($group) - { - $ret = array(); - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - foreach ($group['package'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } - foreach ($group['subpackage'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (!count($ret)) { - return false; - } - return $ret; - } - - // {{{ getChannelValidator() - /** - * @param string channel name - * @return PEAR_Validate|false - */ - function &getChannelValidator($channel) - { - $chan = $this->getChannel($channel); - if (PEAR::isError($chan)) { - return $chan; - } - $val = $chan->getValidationObject(); - return $val; - } - // }}} - // {{{ getChannels() - /** - * @param string channel name - * @return array an array of PEAR_ChannelFile objects representing every installed channel - */ - function &getChannels() - { - $ret = array(); - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - foreach ($this->_listChannels() as $channel) { - $e = &$this->_getChannel($channel); - if (!$e || PEAR::isError($e)) { - continue; - } - $ret[] = $e; - } - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ checkFileMap() - - /** - * Test whether a file or set of files belongs to a package. - * - * If an array is passed in - * @param string|array file path, absolute or relative to the pear - * install dir - * @param string|array name of PEAR package or array('package' => name, 'channel' => - * channel) of a package that will be ignored - * @param string API version - 1.1 will exclude any files belonging to a package - * @param array private recursion variable - * @return array|false which package and channel the file belongs to, or an empty - * string if the file does not belong to an installed package, - * or belongs to the second parameter's package - */ - function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) - { - if (is_array($path)) { - static $notempty; - if (empty($notempty)) { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php'; - } - $notempty = create_function('$a','return !empty($a);'); - } - $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) - : strtolower($package); - $pkgs = array(); - foreach ($path as $name => $attrs) { - if (is_array($attrs)) { - if (isset($attrs['install-as'])) { - $name = $attrs['install-as']; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; - } - if (isset($attrs['baseinstalldir'])) { - $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; - } - } - $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); - if (PEAR::isError($pkgs[$name])) { - return $pkgs[$name]; - } - } - return array_filter($pkgs, $notempty); - } - if (empty($this->filemap_cache)) { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $err = $this->_readFileMap(); - $this->_unlock(); - if (PEAR::isError($err)) { - return $err; - } - } - if (!$attrs) { - $attrs = array('role' => 'php'); // any old call would be for PHP role only - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - $l = strlen($this->install_dir); - if (substr($path, 0, $l) == $this->install_dir) { - $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - return false; - } - - // }}} - // {{{ flush() - /** - * Force a reload of the filemap - * @since 1.5.0RC3 - */ - function flushFileMap() - { - $this->filemap_cache = null; - clearstatcache(); // ensure that the next read gets the full, current filemap - } - - // }}} - // {{{ apiVersion() - /** - * Get the expected API version. Channels API is version 1.1, as it is backwards - * compatible with 1.0 - * @return string - */ - function apiVersion() - { - return '1.1'; - } - // }}} - - - /** - * Parse a package name, or validate a parsed package name array - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',] - * ['group' => 'groupname']) - * or a string of format - * [channel://][channame/]pname[-version|-state][/group=groupname] - * @return array|PEAR_Error - */ - function parsePackageName($param, $defaultchannel = 'pear.php.net') - { - $saveparam = $param; - if (is_array($param)) { - // convert to string for error messages - $saveparam = $this->parsedPackageNameToString($param); - // process the array - if (!isset($param['package'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in index "param"', - 'package', null, null, $param); - } - if (!isset($param['uri'])) { - if (!isset($param['channel'])) { - $param['channel'] = $defaultchannel; - } - } else { - $param['channel'] = '__uri'; - } - } else { - $components = @parse_url((string) $param); - if (isset($components['scheme'])) { - if ($components['scheme'] == 'http') { - // uri package - $param = array('uri' => $param, 'channel' => '__uri'); - } elseif($components['scheme'] != 'channel') { - return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . - 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); - } - } - if (!isset($components['path'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in "' . $param . '"', - 'package', null, null, $param); - } - if (isset($components['host'])) { - // remove the leading "/" - $components['path'] = substr($components['path'], 1); - } - if (!isset($components['scheme'])) { - if (strpos($components['path'], '/') !== false) { - if ($components['path']{0} == '/') { - return PEAR::raiseError('parsePackageName(): this is not ' . - 'a package name, it begins with "/" in "' . $param . '"', - 'invalid', null, null, $param); - } - $parts = explode('/', $components['path']); - $components['host'] = array_shift($parts); - if (count($parts) > 1) { - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } else { - $components['path'] = implode('/', $parts); - } - } else { - $components['host'] = $defaultchannel; - } - } else { - if (strpos($components['path'], '/')) { - $parts = explode('/', $components['path']); - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } - } - - if (is_array($param)) { - $param['package'] = $components['path']; - } else { - $param = array( - 'package' => $components['path'] - ); - if (isset($components['host'])) { - $param['channel'] = $components['host']; - } - } - if (isset($components['fragment'])) { - $param['group'] = $components['fragment']; - } - if (isset($components['user'])) { - $param['user'] = $components['user']; - } - if (isset($components['pass'])) { - $param['pass'] = $components['pass']; - } - if (isset($components['query'])) { - parse_str($components['query'], $param['opts']); - } - // check for extension - $pathinfo = pathinfo($param['package']); - if (isset($pathinfo['extension']) && - in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { - $param['extension'] = $pathinfo['extension']; - $param['package'] = substr($pathinfo['basename'], 0, - strlen($pathinfo['basename']) - 4); - } - // check for version - if (strpos($param['package'], '-')) { - $test = explode('-', $param['package']); - if (count($test) != 2) { - return PEAR::raiseError('parsePackageName(): only one version/state ' . - 'delimiter "-" is allowed in "' . $saveparam . '"', - 'version', null, null, $param); - } - list($param['package'], $param['version']) = $test; - } - } - // validation - $info = $this->channelExists($param['channel']); - if (PEAR::isError($info)) { - return $info; - } - if (!$info) { - return PEAR::raiseError('unknown channel "' . $param['channel'] . - '" in "' . $saveparam . '"', 'channel', null, null, $param); - } - $chan = $this->getChannel($param['channel']); - if (PEAR::isError($chan)) { - return $chan; - } - if (!$chan) { - return PEAR::raiseError("Exception: corrupt registry, could not " . - "retrieve channel " . $param['channel'] . " information", - 'registry', null, null, $param); - } - $param['channel'] = $chan->getName(); - $validate = $chan->getValidationObject(); - $vpackage = $chan->getValidationPackage(); - // validate package name - if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { - return PEAR::raiseError('parsePackageName(): invalid package name "' . - $param['package'] . '" in "' . $saveparam . '"', - 'package', null, null, $param); - } - if (isset($param['group'])) { - if (!PEAR_Validate::validGroupName($param['group'])) { - return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . - '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, - $param); - } - } - if (isset($param['state'])) { - if (!in_array(strtolower($param['state']), $validate->getValidStates())) { - return PEAR::raiseError('parsePackageName(): state "' . $param['state'] - . '" is not a valid state in "' . $saveparam . '"', - 'state', null, null, $param); - } - } - if (isset($param['version'])) { - if (isset($param['state'])) { - return PEAR::raiseError('parsePackageName(): cannot contain both ' . - 'a version and a stability (state) in "' . $saveparam . '"', - 'version/state', null, null, $param); - } - // check whether version is actually a state - if (in_array(strtolower($param['version']), $validate->getValidStates())) { - $param['state'] = strtolower($param['version']); - unset($param['version']); - } else { - if (!$validate->validVersion($param['version'])) { - return PEAR::raiseError('parsePackageName(): "' . $param['version'] . - '" is neither a valid version nor a valid state in "' . - $saveparam . '"', 'version/state', null, null, $param); - } - } - } - return $param; - } - - /** - * @param array - * @return string - */ - function parsedPackageNameToString($parsed, $brief = false) - { - if (is_string($parsed)) { - return $parsed; - } - if (is_object($parsed)) { - $p = $parsed; - $parsed = array( - 'package' => $p->getPackage(), - 'channel' => $p->getChannel(), - 'version' => $p->getVersion(), - ); - } - if (isset($parsed['uri'])) { - return $parsed['uri']; - } - if ($brief) { - if ($channel = $this->channelAlias($parsed['channel'])) { - return $channel . '/' . $parsed['package']; - } - } - $upass = ''; - if (isset($parsed['user'])) { - $upass = $parsed['user']; - if (isset($parsed['pass'])) { - $upass .= ':' . $parsed['pass']; - } - $upass = "$upass@"; - } - $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; - if (isset($parsed['version']) || isset($parsed['state'])) { - $ver = isset($parsed['version']) ? $parsed['version'] : ''; - $ver .= isset($parsed['state']) ? $parsed['state'] : ''; - $ret .= '-' . $ver; - } - if (isset($parsed['extension'])) { - $ret .= '.' . $parsed['extension']; - } - if (isset($parsed['opts'])) { - $ret .= '?'; - foreach ($parsed['opts'] as $name => $value) { - $parsed['opts'][$name] = "$name=$value"; - } - $ret .= implode('&', $parsed['opts']); - } - if (isset($parsed['group'])) { - $ret .= '#' . $parsed['group']; - } - return $ret; - } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: REST.php 286489 2009-07-29 05:59:08Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * For downloading xml files - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php'; - -/** - * Intelligently retrieve data, following hyperlinks if necessary, and re-directing - * as well - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_REST -{ - var $config; - var $_options; - - function PEAR_REST(&$config, $options = array()) - { - $this->config = &$config; - $this->_options = $options; - } - - /** - * Retrieve REST data, but always retrieve the local cache if it is available. - * - * This is useful for elements that should never change, such as information on a particular - * release - * @param string full URL to this resource - * @param array|false contents of the accept-encoding header - * @param boolean if true, xml will be returned as a string, otherwise, xml will be - * parsed using PEAR_XMLParser - * @return string|array - */ - function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) - { - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; - - if (file_exists($cachefile)) { - return unserialize(implode('', file($cachefile))); - } - - return $this->retrieveData($url, $accept, $forcestring, $channel); - } - - /** - * Retrieve a remote REST resource - * @param string full URL to this resource - * @param array|false contents of the accept-encoding header - * @param boolean if true, xml will be returned as a string, otherwise, xml will be - * parsed using PEAR_XMLParser - * @return string|array - */ - function retrieveData($url, $accept = false, $forcestring = false, $channel = false) - { - $cacheId = $this->getCacheId($url); - if ($ret = $this->useLocalCache($url, $cacheId)) { - return $ret; - } - - $file = $trieddownload = false; - if (!isset($this->_options['offline'])) { - $trieddownload = true; - $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel); - } - - if (PEAR::isError($file)) { - if ($file->getCode() !== -9276) { - return $file; - } - - $trieddownload = false; - $file = false; // use local copy if available on socket connect error - } - - if (!$file) { - $ret = $this->getCache($url); - if (!PEAR::isError($ret) && $trieddownload) { - // reset the age of the cache if the server says it was unmodified - $this->saveCache($url, $ret, null, true, $cacheId); - } - - return $ret; - } - - if (is_array($file)) { - $headers = $file[2]; - $lastmodified = $file[1]; - $content = $file[0]; - } else { - $headers = array(); - $lastmodified = false; - $content = $file; - } - - if ($forcestring) { - $this->saveCache($url, $content, $lastmodified, false, $cacheId); - return $content; - } - - if (isset($headers['content-type'])) { - switch ($headers['content-type']) { - case 'text/xml' : - case 'application/xml' : - case 'text/plain' : - if ($headers['content-type'] === 'text/plain') { - $check = substr($content, 0, 5); - if ($check !== 'parse($content); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . - $err->getMessage()); - } - $content = $parser->getData(); - case 'text/html' : - default : - // use it as a string - } - } else { - // assume XML - $parser = new PEAR_XMLParser; - $parser->parse($content); - $content = $parser->getData(); - } - - $this->saveCache($url, $content, $lastmodified, false, $cacheId); - return $content; - } - - function useLocalCache($url, $cacheid = null) - { - if ($cacheid === null) { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - if (!file_exists($cacheidfile)) { - return false; - } - - $cacheid = unserialize(implode('', file($cacheidfile))); - } - - $cachettl = $this->config->get('cache_ttl'); - // If cache is newer than $cachettl seconds, we use the cache! - if (time() - $cacheid['age'] < $cachettl) { - return $this->getCache($url); - } - - return false; - } - - function getCacheId($url) - { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - - if (!file_exists($cacheidfile)) { - return false; - } - - $ret = unserialize(implode('', file($cacheidfile))); - return $ret; - } - - function getCache($url) - { - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; - - if (!file_exists($cachefile)) { - return PEAR::raiseError('No cached content available for "' . $url . '"'); - } - - return unserialize(implode('', file($cachefile))); - } - - /** - * @param string full URL to REST resource - * @param string original contents of the REST resource - * @param array HTTP Last-Modified and ETag headers - * @param bool if true, then the cache id file should be regenerated to - * trigger a new time-to-live value - */ - function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) - { - $cachedir = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . md5($url); - $cacheidfile = $cachedir . 'rest.cacheid'; - $cachefile = $cachedir . 'rest.cachefile'; - - if ($cacheid === null && $nochange) { - $cacheid = unserialize(implode('', file($cacheidfile))); - } - - $fp = @fopen($cacheidfile, 'wb'); - if (!$fp) { - $cache_dir = $this->config->get('cache_dir'); - if (is_dir($cache_dir)) { - return false; - } - - System::mkdir(array('-p', $cache_dir)); - $fp = @fopen($cacheidfile, 'wb'); - if (!$fp) { - return false; - } - } - - if ($nochange) { - fwrite($fp, serialize(array( - 'age' => time(), - 'lastChange' => $cacheid['lastChange'], - )) - ); - - fclose($fp); - return true; - } - - fwrite($fp, serialize(array( - 'age' => time(), - 'lastChange' => $lastmodified, - )) - ); - - fclose($fp); - $fp = @fopen($cachefile, 'wb'); - if (!$fp) { - if (file_exists($cacheidfile)) { - @unlink($cacheidfile); - } - - return false; - } - - fwrite($fp, serialize($contents)); - fclose($fp); - return true; - } - - /** - * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory - * This is best used for small files - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param string $save_dir directory to save file in - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @return string|array Returns the contents of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. - * - * @access public - */ - function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false) - { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); - } - - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); - } - - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; - $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; - - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($this->config->get('http_proxy')&& - $proxy = parse_url($this->config->get('http_proxy')) - ) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if ($schema === 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } - - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - $proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http'; - } - - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; - } - - if (isset($proxy['host'])) { - $request = "GET $url HTTP/1.1\r\n"; - } else { - $request = "GET $path HTTP/1.1\r\n"; - } - - $request .= "Host: $host:$port\r\n"; - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; - } - - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; - } - } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); - } - - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; - - $username = $this->config->get('username', null, $channel); - $password = $this->config->get('password', null, $channel); - - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; - } - - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; - } - - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; - } - - $request .= "Accept-Encoding:\r\n"; - $request .= "Connection: close\r\n"; - $request .= "\r\n"; - - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); - if (!$fp) { - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276); - } - } else { - if ($schema === 'https') { - $host = 'ssl://' . $host; - } - - $fp = @fsockopen($host, $port, $errno, $errstr); - if (!$fp) { - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); - } - } - - fwrite($fp, $request); - - $headers = array(); - $reply = 0; - while ($line = trim(fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; - } - - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)"); - } - } - } - - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)"); - } - - if ($wasredirect > 4) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)"); - } - - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel); - } - - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - - $data = ''; - while ($chunk = @fread($fp, 8192)) { - $data .= $chunk; - } - fclose($fp); - - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); - } - - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; - } else { - $lastmodified = $headers['last-modified']; - } - } - - return array($data, $lastmodified, $headers); - } - - return $data; - } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 10.php 287558 2009-08-21 22:21:28Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a12 - */ - -/** - * For downloading REST xml/txt files - */ -require_once 'phar://go-pear.phar/' . 'PEAR/REST.php'; - -/** - * Implement REST 1.0 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a12 - */ -class PEAR_REST_10 -{ - /** - * @var PEAR_REST - */ - var $_rest; - function PEAR_REST_10($config, $options = array()) - { - $this->_rest = &new PEAR_REST($config, $options); - } - - /** - * Retrieve information about a remote package to be downloaded from a REST server - * - * @param string $base The uri to prepend to all REST calls - * @param array $packageinfo an array of format: - *
    -     *  array(
    -     *   'package' => 'packagename',
    -     *   'channel' => 'channelname',
    -     *  ['state' => 'alpha' (or valid state),]
    -     *  -or-
    -     *  ['version' => '1.whatever']
    -     * 
    - * @param string $prefstate Current preferred_state config variable value - * @param bool $installed the installed version of this package to compare against - * @return array|false|PEAR_Error see {@link _returnDownloadURL()} - */ - function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) - { - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $channel = $packageinfo['channel']; - $package = $packageinfo['package']; - $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; - $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; - $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; - - $info = $this->_rest->retrieveData($restFile, false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('No releases available for package "' . - $channel . '/' . $package . '"'); - } - - if (!isset($info['r'])) { - return false; - } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - - if (isset($state)) { - // try our preferred state first - if ($release['s'] == $state) { - $found = true; - break; - } - // see if there is something newer and more stable - // bug #7221 - if (in_array($release['s'], $this->betterStates($state), true)) { - $found = true; - break; - } - } elseif (isset($version)) { - if ($release['v'] == $version) { - $found = true; - break; - } - } else { - if (in_array($release['s'], $states)) { - $found = true; - break; - } - } - } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); - } - - function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, - $prefstate = 'stable', $installed = false, $channel = false) - { - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $channel = $dependency['channel']; - $package = $dependency['name']; - $state = isset($dependency['state']) ? $dependency['state'] : null; - $version = isset($dependency['version']) ? $dependency['version'] : null; - $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; - - $info = $this->_rest->retrieveData($restFile, false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] - . '" dependency "' . $channel . '/' . $package . '" has no releases'); - } - - if (!is_array($info) || !isset($info['r'])) { - return false; - } - - $exclude = array(); - $min = $max = $recommended = false; - if ($xsdversion == '1.0') { - switch ($dependency['rel']) { - case 'ge' : - $min = $dependency['version']; - break; - case 'gt' : - $min = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'eq' : - $recommended = $dependency['version']; - break; - case 'lt' : - $max = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'le' : - $max = $dependency['version']; - break; - case 'ne' : - $exclude = array($dependency['version']); - break; - } - } else { - $min = isset($dependency['min']) ? $dependency['min'] : false; - $max = isset($dependency['max']) ? $dependency['max'] : false; - $recommended = isset($dependency['recommended']) ? - $dependency['recommended'] : false; - if (isset($dependency['exclude'])) { - if (!isset($dependency['exclude'][0])) { - $exclude = array($dependency['exclude']); - } - } - } - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - if (in_array($release['v'], $exclude)) { // skip excluded versions - continue; - } - // allow newer releases to say "I'm OK with the dependent package" - if ($xsdversion == '2.0' && isset($release['co'])) { - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - foreach ($release['co'] as $entry) { - if (isset($entry['x']) && !is_array($entry['x'])) { - $entry['x'] = array($entry['x']); - } elseif (!isset($entry['x'])) { - $entry['x'] = array(); - } - if ($entry['c'] == $deppackage['channel'] && - strtolower($entry['p']) == strtolower($deppackage['package']) && - version_compare($deppackage['version'], $entry['min'], '>=') && - version_compare($deppackage['version'], $entry['max'], '<=') && - !in_array($release['v'], $entry['x'])) { - $recommended = $release['v']; - break; - } - } - } - if ($recommended) { - if ($release['v'] != $recommended) { // if we want a specific - // version, then skip all others - continue; - } else { - if (!in_array($release['s'], $states)) { - // the stability is too low, but we must return the - // recommended version if possible - return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); - } - } - } - if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions - continue; - } - if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions - continue; - } - if ($installed && version_compare($release['v'], $installed, '<')) { - continue; - } - if (in_array($release['s'], $states)) { // if in the preferred state... - $found = true; // ... then use it - break; - } - } - return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); - } - - /** - * Take raw data and return the array needed for processing a download URL - * - * @param string $base REST base uri - * @param string $package Package name - * @param array $release an array of format array('v' => version, 's' => state) - * describing the release to download - * @param array $info list of all releases as defined by allreleases.xml - * @param bool|null $found determines whether the release was found or this is the next - * best alternative. If null, then versions were skipped because - * of PHP dependency - * @return array|PEAR_Error - * @access private - */ - function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false) - { - if (!$found) { - $release = $info['r'][0]; - } - - $packageLower = strtolower($package); - $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' . - 'info.xml', false, false, $channel); - if (PEAR::isError($pinfo)) { - return PEAR::raiseError('Package "' . $package . - '" does not have REST info xml available'); - } - - $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . - $release['v'] . '.xml', false, false, $channel); - if (PEAR::isError($releaseinfo)) { - return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . - '" does not have REST xml available'); - } - - $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . - 'deps.' . $release['v'] . '.txt', false, true, $channel); - if (PEAR::isError($packagexml)) { - return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . - '" does not have REST dependency information available'); - } - - $packagexml = unserialize($packagexml); - if (!$packagexml) { - $packagexml = array(); - } - - $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower . - '/allreleases.xml', false, false, $channel); - if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { - $allinfo['r'] = array($allinfo['r']); - } - - $compatible = false; - foreach ($allinfo['r'] as $release) { - if ($release['v'] != $releaseinfo['v']) { - continue; - } - - if (!isset($release['co'])) { - break; - } - - $compatible = array(); - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - - foreach ($release['co'] as $entry) { - $comp = array(); - $comp['name'] = $entry['p']; - $comp['channel'] = $entry['c']; - $comp['min'] = $entry['min']; - $comp['max'] = $entry['max']; - if (isset($entry['x']) && !is_array($entry['x'])) { - $comp['exclude'] = $entry['x']; - } - - $compatible[] = $comp; - } - - if (count($compatible) == 1) { - $compatible = $compatible[0]; - } - - break; - } - - $deprecated = false; - if (isset($pinfo['dc']) && isset($pinfo['dp'])) { - if (is_array($pinfo['dp'])) { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp']['_content'])); - } else { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp'])); - } - } - - $return = array( - 'version' => $releaseinfo['v'], - 'info' => $packagexml, - 'package' => $releaseinfo['p']['_content'], - 'stability' => $releaseinfo['st'], - 'compatible' => $compatible, - 'deprecated' => $deprecated, - ); - - if ($found) { - $return['url'] = $releaseinfo['g']; - return $return; - } - - $return['php'] = $phpversion; - return $return; - } - - function listPackages($base, $channel = false) - { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return array(); - } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - return $packagelist['p']; - } - - /** - * List all categories of a REST server - * - * @param string $base base URL of the server - * @return array of categorynames - */ - function listCategories($base, $channel = false) - { - $categories = array(); - - // c/categories.xml does not exist; - // check for every package its category manually - // This is SLOOOWWWW : /// - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - if (!is_array($packagelist) || !isset($packagelist['p'])) { - $ret = array(); - return $ret; - } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($packagelist['p'] as $package) { - $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($inf)) { - PEAR::popErrorHandling(); - return $inf; - } - $cat = $inf['ca']['_content']; - if (!isset($categories[$cat])) { - $categories[$cat] = $inf['ca']; - } - } - - return array_values($categories); - } - - /** - * List a category of a REST server - * - * @param string $base base URL of the server - * @param string $category name of the category - * @param boolean $info also download full package info - * @return array of packagenames - */ - function listCategory($base, $category, $info = false, $channel = false) - { - // gives '404 Not Found' error when category doesn't exist - $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return array(); - } - - if (!is_array($packagelist['p']) || - !isset($packagelist['p'][0])) { // only 1 pkg - $packagelist = array($packagelist['p']); - } else { - $packagelist = $packagelist['p']; - } - - if ($info == true) { - // get individual package info - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($packagelist as $i => $packageitem) { - $url = sprintf('%s'.'r/%s/latest.txt', - $base, - strtolower($packageitem['_content'])); - $version = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($version)) { - break; // skipit - } - $url = sprintf('%s'.'r/%s/%s.xml', - $base, - strtolower($packageitem['_content']), - $version); - $info = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($info)) { - break; // skipit - } - $packagelist[$i]['info'] = $info; - } - PEAR::popErrorHandling(); - } - - return $packagelist; - } - - - function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) - { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if ($this->_rest->config->get('verbose') > 0) { - $ui = &PEAR_Frontend::singleton(); - $ui->log('Retrieving data...0%', true); - } - $ret = array(); - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return $ret; - } - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - // only search-packagename = quicksearch ! - if ($searchpackage && (!$searchsummary || empty($searchpackage))) { - $newpackagelist = array(); - foreach ($packagelist['p'] as $package) { - if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) { - $newpackagelist[] = $package; - } - } - $packagelist['p'] = $newpackagelist; - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $next = .1; - foreach ($packagelist['p'] as $progress => $package) { - if ($this->_rest->config->get('verbose') > 0) { - if ($progress / count($packagelist['p']) >= $next) { - if ($next == .5) { - $ui->log('50%', false); - } else { - $ui->log('.', false); - } - $next += .1; - } - } - - if ($basic) { // remote-list command - if ($dostable) { - $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/stable.txt', false, false, $channel); - } else { - $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/latest.txt', false, false, $channel); - } - if (PEAR::isError($latest)) { - $latest = false; - } - $info = array('stable' => $latest); - } else { // list-all command - $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($inf)) { - PEAR::popErrorHandling(); - return $inf; - } - if ($searchpackage) { - $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false); - if (!$found && !(isset($searchsummary) && !empty($searchsummary) - && (stristr($inf['s'], $searchsummary) !== false - || stristr($inf['d'], $searchsummary) !== false))) - { - continue; - }; - } - $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (PEAR::isError($releases)) { - continue; - } - if (!isset($releases['r'][0])) { - $releases['r'] = array($releases['r']); - } - unset($latest); - unset($unstable); - unset($stable); - unset($state); - foreach ($releases['r'] as $release) { - if (!isset($latest)) { - if ($dostable && $release['s'] == 'stable') { - $latest = $release['v']; - $state = 'stable'; - } - if (!$dostable) { - $latest = $release['v']; - $state = $release['s']; - } - } - if (!isset($stable) && $release['s'] == 'stable') { - $stable = $release['v']; - if (!isset($unstable)) { - $unstable = $stable; - } - } - if (!isset($unstable) && $release['s'] != 'stable') { - $latest = $unstable = $release['v']; - $state = $release['s']; - } - if (isset($latest) && !isset($state)) { - $state = $release['s']; - } - if (isset($latest) && isset($stable) && isset($unstable)) { - break; - } - } - $deps = array(); - if (!isset($unstable)) { - $unstable = false; - $state = 'stable'; - if (isset($stable)) { - $latest = $unstable = $stable; - } - } else { - $latest = $unstable; - } - if (!isset($latest)) { - $latest = false; - } - if ($latest) { - $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . - $latest . '.txt', false, false, $channel); - if (!PEAR::isError($d)) { - $d = unserialize($d); - if ($d) { - if (isset($d['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; - } - if (!isset($pf)) { - $pf = new PEAR_PackageFile_v2; - } - $pf->setDeps($d); - $tdeps = $pf->getDeps(); - } else { - $tdeps = $d; - } - foreach ($tdeps as $dep) { - if ($dep['type'] !== 'pkg') { - continue; - } - $deps[] = $dep; - } - } - } - } - if (!isset($stable)) { - $stable = '-n/a-'; - } - if (!$searchpackage) { - $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' => - $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - } else { - $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' => - $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - } - } - $ret[$package] = $info; - } - PEAR::popErrorHandling(); - return $ret; - } - - function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg) - { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - - $ret = array(); - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return $ret; - } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } - - foreach ($packagelist['p'] as $package) { - if (!isset($installed[strtolower($package)])) { - continue; - } - - $inst_version = $reg->packageInfo($package, 'version', $channel); - $inst_state = $reg->packageInfo($package, 'release_state', $channel); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - PEAR::popErrorHandling(); - if (PEAR::isError($info)) { - continue; // no remote releases - } - - if (!isset($info['r'])) { - continue; - } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - // $info['r'] is sorted by version number - usort($info['r'], array($this, '_sortReleasesByVersionNumber')); - foreach ($info['r'] as $release) { - if ($inst_version && version_compare($release['v'], $inst_version, '<=')) { - // not newer than the one installed - break; - } - - // new version > installed version - if (!$pref_state) { - // every state is a good state - $found = true; - break; - } else { - $new_state = $release['s']; - // if new state >= installed state: go - if (in_array($new_state, $this->betterStates($inst_state, true))) { - $found = true; - break; - } else { - // only allow to lower the state of package, - // if new state >= preferred state: go - if (in_array($new_state, $this->betterStates($pref_state, true))) { - $found = true; - break; - } - } - } - } - - if (!$found) { - continue; - } - - $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . - $release['v'] . '.xml', false, false, $channel); - if (PEAR::isError($relinfo)) { - return $relinfo; - } - - $ret[$package] = array( - 'version' => $release['v'], - 'state' => $release['s'], - 'filesize' => $relinfo['f'], - ); - } - - return $ret; - } - - function packageInfo($base, $package, $channel = false) - { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($pinfo)) { - PEAR::popErrorHandling(); - return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' . - $pinfo->getMessage()); - } - - $releases = array(); - $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (!PEAR::isError($allreleases)) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php'; - } - - if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) { - $allreleases['r'] = array($allreleases['r']); - } - - $pf = new PEAR_PackageFile_v2; - foreach ($allreleases['r'] as $release) { - $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . - $release['v'] . '.txt', false, false, $channel); - if (PEAR::isError($ds)) { - continue; - } - - if (!isset($latest)) { - $latest = $release['v']; - } - - $pf->setDeps(unserialize($ds)); - $ds = $pf->getDeps(); - $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) - . '/' . $release['v'] . '.xml', false, false, $channel); - - if (PEAR::isError($info)) { - continue; - } - - $releases[$release['v']] = array( - 'doneby' => $info['m'], - 'license' => $info['l'], - 'summary' => $info['s'], - 'description' => $info['d'], - 'releasedate' => $info['da'], - 'releasenotes' => $info['n'], - 'state' => $release['s'], - 'deps' => $ds ? $ds : array(), - ); - } - } else { - $latest = ''; - } - - PEAR::popErrorHandling(); - if (isset($pinfo['dc']) && isset($pinfo['dp'])) { - if (is_array($pinfo['dp'])) { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp']['_content'])); - } else { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp'])); - } - } else { - $deprecated = false; - } - - if (!isset($latest)) { - $latest = ''; - } - - return array( - 'name' => $pinfo['n'], - 'channel' => $pinfo['c'], - 'category' => $pinfo['ca']['_content'], - 'stable' => $latest, - 'license' => $pinfo['l'], - 'summary' => $pinfo['s'], - 'description' => $pinfo['d'], - 'releases' => $releases, - 'deprecated' => $deprecated, - ); - } - - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - - if ($include) { - $i--; - } - - return array_slice($states, $i + 1); - } - - /** - * Sort releases by version number - * - * @access private - */ - function _sortReleasesByVersionNumber($a, $b) - { - if (version_compare($a['v'], $b['v'], '=')) { - return 0; - } - - if (version_compare($a['v'], $b['v'], '>')) { - return -1; - } - - if (version_compare($a['v'], $b['v'], '<')) { - return 1; - } - } -} 'Installation base ($prefix)', - 'temp_dir' => 'Temporary directory for processing', - 'download_dir' => 'Temporary directory for downloads', - 'bin_dir' => 'Binaries directory', - 'php_dir' => 'PHP code directory ($php_dir)', - 'doc_dir' => 'Documentation directory', - 'data_dir' => 'Data directory', - 'cfg_dir' => 'User-modifiable configuration files directory', - 'www_dir' => 'Public Web Files directory', - 'test_dir' => 'Tests directory', - 'pear_conf' => 'Name of configuration file', - ); - var $localInstall; - var $PEARConfig; - var $tarball = array(); - function PEAR_Start() - { - parent::PEAR(); - if (OS_WINDOWS) { - $this->configPrompt['php_bin'] = 'Path to CLI php.exe'; - $this->config[] = 'php_bin'; - $this->prefix = getcwd(); - - if (!@is_dir($this->prefix)) { - if (@is_dir('c:\php5')) { - $this->prefix = 'c:\php5'; - } elseif (@is_dir('c:\php4')) { - $this->prefix = 'c:\php4'; - } elseif (@is_dir('c:\php')) { - $this->prefix = 'c:\php'; - } - } - - $this->localInstall = false; - $this->bin_dir = '$prefix'; - $this->temp_dir = '$prefix\tmp'; - $this->download_dir = '$prefix\tmp'; - $this->php_dir = '$prefix\pear'; - $this->doc_dir = '$prefix\docs'; - $this->data_dir = '$prefix\data'; - $this->test_dir = '$prefix\tests'; - $this->www_dir = '$prefix\www'; - $this->cfg_dir = '$prefix\cfg'; - $this->pear_conf = PEAR_CONFIG_SYSCONFDIR . '\\pear.ini'; - /* - * Detects php.exe - */ - $this->validPHPBin = true; - if ($t = $this->safeGetenv('PHP_PEAR_PHP_BIN')) { - $this->php_bin = dirname($t); - } elseif ($t = $this->safeGetenv('PHP_BIN')) { - $this->php_bin = dirname($t); - } elseif ($t = System::which('php')) { - $this->php_bin = dirname($t); - } elseif (is_file($this->prefix . '\cli\php.exe')) { - $this->php_bin = $this->prefix . '\cli'; - } elseif (is_file($this->prefix . '\php.exe')) { - $this->php_bin = $this->prefix; - } - $phpexe = OS_WINDOWS ? '\\php.exe' : '/php'; - if ($this->php_bin && !is_file($this->php_bin . $phpexe)) { - $this->php_bin = ''; - } else { - if (strpos($this->php_bin, ':') === 0) { - $this->php_bin = getcwd() . DIRECTORY_SEPARATOR . $this->php_bin; - } - } - if (!is_file($this->php_bin . $phpexe)) { - if (is_file('c:/php/cli/php.exe')) { - $this->php_bin = 'c"\\php\\cli'; - } elseif (is_file('c:/php5/php.exe')) { - $this->php_bin = 'c:\\php5'; - } elseif (is_file('c:/php4/cli/php.exe')) { - $this->php_bin = 'c:\\php4\\cli'; - } else { - $this->validPHPBin = false; - } - } - } else { - $this->prefix = dirname(PHP_BINDIR); - $this->pear_conf = PEAR_CONFIG_SYSCONFDIR . '/pear.conf'; - if (get_current_user() != 'root') { - $this->prefix = $this->safeGetenv('HOME') . '/pear'; - $this->pear_conf = $this->safeGetenv('HOME') . '.pearrc'; - } - $this->bin_dir = '$prefix/bin'; - $this->php_dir = '$prefix/share/pear'; - $this->temp_dir = '/tmp/pear/install'; - $this->download_dir = '/tmp/pear/install'; - $this->doc_dir = '$prefix/docs'; - $this->www_dir = '$prefix/www'; - $this->cfg_dir = '$prefix/cfg'; - $this->data_dir = '$prefix/data'; - $this->test_dir = '$prefix/tests'; - // check if the user has installed PHP with PHP or GNU layout - if (@is_dir("$this->prefix/lib/php/.registry")) { - $this->php_dir = '$prefix/lib/php'; - } elseif (@is_dir("$this->prefix/share/pear/lib/.registry")) { - $this->php_dir = '$prefix/share/pear/lib'; - $this->doc_dir = '$prefix/share/pear/docs'; - $this->data_dir = '$prefix/share/pear/data'; - $this->test_dir = '$prefix/share/pear/tests'; - } elseif (@is_dir("$this->prefix/share/php/.registry")) { - $this->php_dir = '$prefix/share/php'; - } - } - } - - function safeGetenv($var) - { - if (is_array($_ENV) && isset($_ENV[$var])) { - return $_ENV[$var]; - } - return getenv($var); - } - - function show($stuff) - { - print $stuff; - } - - function locatePackagesToInstall() - { - $dp = @opendir(dirname(__FILE__) . '/go-pear-tarballs'); - if (empty($dp)) { - return PEAR::raiseError("while locating packages to install: opendir('" . - dirname(__FILE__) . "/go-pear-tarballs') failed"); - } - $potentials = array(); - while (false !== ($entry = readdir($dp))) { - if ($entry{0} == '.' || !in_array(substr($entry, -4), array('.tar', '.tgz'))) { - continue; - } - $potentials[] = $entry; - } - closedir($dp); - $notfound = array(); - foreach ($this->corePackages as $package) { - foreach ($potentials as $i => $candidate) { - if (preg_match('/^' . $package . '-' . _PEAR_COMMON_PACKAGE_VERSION_PREG - . '\.(tar|tgz)\\z/', $candidate)) { - $this->tarball[$package] = dirname(__FILE__) . '/go-pear-tarballs/' . $candidate; - unset($potentials[$i]); - continue 2; - } - } - $notfound[] = $package; - } - if (count($notfound)) { - return PEAR::raiseError("No tarballs found for core packages: " . - implode(', ', $notfound)); - } - $this->tarball = array_merge($this->tarball, $potentials); - } - - function setupTempStuff() - { - if (!($this->ptmp = System::mktemp(array('-d')))) { - $this->show("System's Tempdir failed, trying to use \$prefix/tmp ..."); - $res = System::mkDir(array($this->prefix . '/tmp')); - if (!$res) { - return PEAR::raiseError('mkdir ' . $this->prefix . '/tmp ... failed'); - } - $_temp = tempnam($this->prefix . '/tmp', 'gope'); - - System::rm(array('-rf', $_temp)); - System::mkdir(array('-p','-m', '0700', $_temp)); - $this->ptmp = $this->prefix . '/tmp'; - $ok = @chdir($this->ptmp); - - if (!$ok) { // This should not happen, really ;) - $this->bail('chdir ' . $this->ptmp . ' ... failed'); - } - - print "ok\n"; - - // Adjust TEMPDIR envvars - if (!isset($_ENV)) { - $_ENV = array(); - }; - $_ENV['TMPDIR'] = $_ENV['TEMP'] = $this->prefix . '/tmp'; - } - return @chdir($this->ptmp); - } - - /** - * Try to detect the kind of SAPI used by the - * the given php.exe. - * @author Pierrre-Alain Joye - */ - function win32DetectPHPSAPI() - { - if ($this->php_bin != '') { - if (OS_WINDOWS) { - exec('"' . $this->php_bin . '\\php.exe" -v', $res); - } else { - exec('"' . $this->php_bin . '/php" -v', $res); - } - if (is_array($res)) { - if (isset($res[0]) && strpos($res[0],"(cli)")) { - return 'cli'; - } - if (isset($res[0]) && strpos($res[0],"cgi")) { - return 'cgi'; - } - if (isset($res[0]) && strpos($res[0],"cgi-fcgi")) { - return 'cgi'; - } else { - return 'unknown'; - } - } - } - return 'unknown'; - } - - function doInstall() - { - print "Beginning install...\n"; - // finish php_bin config - if (OS_WINDOWS) { - $this->php_bin .= '\\php.exe'; - } else { - $this->php_bin .= '/php'; - } - $this->PEARConfig = &PEAR_Config::singleton($this->pear_conf, $this->pear_conf); - $this->PEARConfig->set('preferred_state', 'stable'); - foreach ($this->config as $var) { - if ($var == 'pear_conf' || $var == 'prefix') { - continue; - } - $this->PEARConfig->set($var, $this->$var); - } - - $this->PEARConfig->store(); -// $this->PEARConfig->set('verbose', 6); - print "Configuration written to $this->pear_conf...\n"; - $this->registry = &$this->PEARConfig->getRegistry(); - print "Initialized registry...\n"; - $install = &PEAR_Command::factory('install', $this->PEARConfig); - print "Preparing to install...\n"; - $options = array( - 'nodeps' => true, - 'force' => true, - 'upgrade' => true, - ); - foreach ($this->tarball as $pkg => $src) { - print "installing $src...\n"; - } - $install->run('install', $options, array_values($this->tarball)); - } - - function postProcessConfigVars() - { - foreach ($this->config as $n => $var) { - for ($m = 1; $m <= count($this->config); $m++) { - $var2 = $this->config[$m]; - $this->$var = str_replace('$'.$var2, $this->$var2, $this->$var); - } - } - - foreach ($this->config as $var) { - $dir = $this->$var; - - if (!preg_match('/_dir\\z/', $var)) { - continue; - } - - if (!@is_dir($dir)) { - if (!System::mkDir(array('-p', $dir))) { - $root = OS_WINDOWS ? 'administrator' : 'root'; - return PEAR::raiseError("Unable to create {$this->configPrompt[$var]} $dir. -Run this script as $root or pick another location.\n"); - } - } - } - } - - /** - * Get the php.ini file used with the current - * process or with the given php.exe - * - * Horrible hack, but well ;) - * - * Not used yet, will add the support later - * @author Pierre-Alain Joye - */ - function getPhpiniPath() - { - $pathIni = get_cfg_var('cfg_file_path'); - if ($pathIni && is_file($pathIni)) { - return $pathIni; - } - - // Oh well, we can keep this too :) - // I dunno if get_cfg_var() is safe on every OS - if (OS_WINDOWS) { - // on Windows, we can be pretty sure that there is a php.ini - // file somewhere - do { - $php_ini = PHP_CONFIG_FILE_PATH . DIRECTORY_SEPARATOR . 'php.ini'; - if (@file_exists($php_ini)) { - break; - } - $php_ini = 'c:\winnt\php.ini'; - if (@file_exists($php_ini)) { - break; - } - $php_ini = 'c:\windows\php.ini'; - } while (false); - } else { - $php_ini = PHP_CONFIG_FILE_PATH . DIRECTORY_SEPARATOR . 'php.ini'; - } - - if (@is_file($php_ini)) { - return $php_ini; - } - - // We re running in hackz&troubles :) - ob_implicit_flush(false); - ob_start(); - phpinfo(INFO_GENERAL); - $strInfo = ob_get_contents(); - ob_end_clean(); - ob_implicit_flush(true); - - if (php_sapi_name() != 'cli') { - $strInfo = strip_tags($strInfo,''); - $arrayInfo = explode("", $strInfo ); - $cli = false; - } else { - $arrayInfo = explode("\n", $strInfo); - $cli = true; - } - - foreach ($arrayInfo as $val) { - if (strpos($val,"php.ini")) { - if ($cli) { - list(,$pathIni) = explode('=>', $val); - } else { - $pathIni = strip_tags(trim($val)); - } - $pathIni = trim($pathIni); - if (is_file($pathIni)) { - return $pathIni; - } - } - } - - return false; - } -} -?> -tty = OS_WINDOWS ? @fopen('\con', 'r') : @fopen('/dev/tty', 'r'); - - if (!$this->tty) { - $this->tty = fopen('php://stdin', 'r'); - } - $this->origpwd = getcwd(); - $this->config = array_keys($this->configPrompt); - - // make indices run from 1... - array_unshift($this->config, ""); - unset($this->config[0]); - reset($this->config); - $this->descLength = max(array_map('strlen', $this->configPrompt)); - $this->descFormat = "%-{$this->descLength}s"; - $this->first = key($this->config); - end($this->config); - $this->last = key($this->config); - PEAR_Command::setFrontendType('CLI'); - } - - function _PEAR_Start_CLI() - { - if ($this->tty) { - @fclose($this->tty); - } - } - - function run() - { - if (PEAR::isError($err = $this->locatePackagesToInstall())) { - return $err; - } - $this->startupQuestion(); - $this->setupTempStuff(); - $this->getInstallLocations(); - $this->displayPreamble(); - if (PEAR::isError($err = $this->postProcessConfigVars())) { - return $err; - } - $this->doInstall(); - $this->finishInstall(); - } - - function startupQuestion() - { - if (OS_WINDOWS) { - print " -Are you installing a system-wide PEAR or a local copy? -(system|local) [system] : "; - $tmp = trim(fgets($this->tty, 1024)); - if (!empty($tmp)) { - if (strtolower($tmp) !== 'system') { - print "Please confirm local copy by typing 'yes' : "; - $tmp = trim(fgets($this->tty, 1024)); - if (strtolower($tmp) == 'yes') { - $this->localInstall = true; - $this->pear_conf = '$prefix\\pear.ini'; - } - } - } - } else { - if (get_current_user() == 'root') { - return; - } - $this->pear_conf = $this->safeGetenv('HOME') . '/.pearrc'; - } - } - - function getInstallLocations() - { - while (true) { - print " -Below is a suggested file layout for your new PEAR installation. To -change individual locations, type the number in front of the -directory. Type 'all' to change all of them or simply press Enter to -accept these locations. - -"; - - foreach ($this->config as $n => $var) { - $fullvar = $this->$var; - foreach ($this->config as $blah => $unused) { - foreach ($this->config as $m => $var2) { - $fullvar = str_replace('$'.$var2, $this->$var2, $fullvar); - } - } - printf("%2d. $this->descFormat : %s\n", $n, $this->configPrompt[$var], $fullvar); - } - - print "\n$this->first-$this->last, 'all' or Enter to continue: "; - $tmp = trim(fgets($this->tty, 1024)); - if (empty($tmp)) { - if (OS_WINDOWS && !$this->validPHPBin) { - echo "**ERROR** -Please, enter the php.exe path. - -"; - } else { - break; - } - } - if (isset($this->config[(int)$tmp])) { - $var = $this->config[(int)$tmp]; - $desc = $this->configPrompt[$var]; - $current = $this->$var; - if (WIN32GUI && $var != 'pear_conf'){ - $tmp = $this->win32BrowseForFolder("Choose a Folder for $desc [$current] :"); - } else { - print "(Use \$prefix as a shortcut for '$this->prefix', etc.) -$desc [$current] : "; - $tmp = trim(fgets($this->tty, 1024)); - } - $old = $this->$var; - $this->$var = $$var = $tmp; - if (OS_WINDOWS && $var=='php_bin') { - if ($this->validatePhpExecutable($tmp)) { - $this->php_bin = $tmp; - } else { - $this->php_bin = $old; - } - } - } elseif ($tmp == 'all') { - foreach ($this->config as $n => $var) { - $desc = $this->configPrompt[$var]; - $current = $this->$var; - print "$desc [$current] : "; - $tmp = trim(fgets($this->tty, 1024)); - if (!empty($tmp)) { - $this->$var = $tmp; - } - } - } - } - } - - function validatePhpExecutable($tmp) - { - if (OS_WINDOWS) { - if (strpos($tmp, 'php.exe')) { - $tmp = str_replace('php.exe', '', $tmp); - } - if (file_exists($tmp . DIRECTORY_SEPARATOR . 'php.exe')) { - $tmp = $tmp . DIRECTORY_SEPARATOR . 'php.exe'; - $this->php_bin_sapi = $this->win32DetectPHPSAPI(); - if ($this->php_bin_sapi=='cgi'){ - print " -****************************************************************************** -NOTICE! We found php.exe under $this->php_bin, it uses a $this->php_bin_sapi SAPI. -PEAR commandline tool works well with it. -If you have a CLI php.exe available, we recommend using it. - -Press Enter to continue..."; - $tmp = trim(fgets($this->tty, 1024)); - } elseif ($this->php_bin_sapi=='unknown') { - print " -****************************************************************************** -WARNING! We found php.exe under $this->php_bin, it uses an $this->php_bin_sapi SAPI. -PEAR commandline tool has NOT been tested with it. -If you have a CLI (or CGI) php.exe available, we strongly recommend using it. - -Press Enter to continue..."; - $tmp = trim(fgets($this->tty, 1024)); - } - echo "php.exe (sapi: $this->php_bin_sapi) found.\n\n"; - return $this->validPHPBin = true; - } else { - echo "**ERROR**: not a folder, or no php.exe found in this folder. -Press Enter to continue..."; - $tmp = trim(fgets($this->tty, 1024)); - return $this->validPHPBin = false; - } - } - } - - /** - * Create a vbs script to browse the getfolder dialog, called - * by cscript, if it's available. - * $label is the label text in the header of the dialog box - * - * TODO: - * - Do not show Control panel - * - Replace WSH with calls to w32 as soon as callbacks work - * @author Pierrre-Alain Joye - */ - function win32BrowseForFolder($label) - { - static $wshSaved=false; - static $cscript=''; - $wsh_browserfolder = 'Option Explicit -Dim ArgObj, var1, var2, sa, sFld -Set ArgObj = WScript.Arguments -Const BIF_EDITBOX = &H10 -Const BIF_NEWDIALOGSTYLE = &H40 -Const BIF_RETURNONLYFSDIRS = &H0001 -Const BIF_DONTGOBELOWDOMAIN = &H0002 -Const BIF_STATUSTEXT = &H0004 -Const BIF_RETURNFSANCESTORS = &H0008 -Const BIF_VALIDATE = &H0020 -Const BIF_BROWSEFORCOMPUTER = &H1000 -Const BIF_BROWSEFORPRINTER = &H2000 -Const BIF_BROWSEINCLUDEFILES = &H4000 -Const OFN_LONGNAMES = &H200000 -Const OFN_NOLONGNAMES = &H40000 -Const ssfDRIVES = &H11 -Const ssfNETWORK = &H12 -Set sa = CreateObject("Shell.Application") -var1=ArgObj(0) -Set sFld = sa.BrowseForFolder(0, var1, BIF_EDITBOX + BIF_VALIDATE + BIF_BROWSEINCLUDEFILES + BIF_RETURNFSANCESTORS+BIF_NEWDIALOGSTYLE , ssfDRIVES ) -if not sFld is nothing Then - if not left(sFld.items.item.path,1)=":" Then - WScript.Echo sFld.items.item.path - Else - WScript.Echo "invalid" - End If -Else - WScript.Echo "cancel" -End If -'; - if( !$wshSaved){ - $cscript = $this->ptmp . DIRECTORY_SEPARATOR . "bf.vbs"; - $fh = fopen($cscript, "wb+"); - fwrite($fh, $wsh_browserfolder, strlen($wsh_browserfolder)); - fclose($fh); - $wshSaved = true; - } - exec('cscript ' . $cscript . ' "' . $label . '" //noLogo', $arPath); - if (!count($arPath) || $arPath[0]=='' || $arPath[0]=='cancel') { - return ''; - } elseif ($arPath[0]=='invalid') { - echo "Invalid Path.\n"; - return ''; - } - return $arPath[0]; - } - - function displayPreamble() - { - if (OS_WINDOWS) { - /* - * Checks PHP SAPI version under windows/CLI - */ - if ($this->php_bin == '') { - print " -We do not find any php.exe, please select the php.exe folder (CLI is -recommended, usually in c:\php\cli\php.exe) -"; - $this->validPHPBin = false; - } elseif (strlen($this->php_bin)) { - $this->php_bin_sapi = $this->win32DetectPHPSAPI(); - $this->validPHPBin = true; - switch ($this->php_bin_sapi) { - case 'cli': - break; - case 'cgi': - case 'cgi-fcgi': - print " -*NOTICE* -We found php.exe under $this->php_bin, it uses a $this->php_bin_sapi SAPI. PEAR commandline -tool works well with it, if you have a CLI php.exe available, we -recommend using it. -"; - break; - default: - print " -*WARNING* -We found php.exe under $this->php_bin, it uses an unknown SAPI. PEAR commandline -tool has not been tested with it, if you have a CLI (or CGI) php.exe available, -we strongly recommend using it. - -"; - break; - } - } - } - } - - function finishInstall() - { - $sep = OS_WINDOWS ? ';' : ':'; - $include_path = explode($sep, ini_get('include_path')); - if (OS_WINDOWS) { - $found = false; - $t = strtolower($this->php_dir); - foreach ($include_path as $path) { - if ($t == strtolower($path)) { - $found = true; - break; - } - } - } else { - $found = in_array($this->php_dir, $include_path); - } - if (!$found) { - print " -****************************************************************************** -WARNING! The include_path defined in the currently used php.ini does not -contain the PEAR PHP directory you just specified: -<$this->php_dir> -If the specified directory is also not in the include_path used by -your scripts, you will have problems getting any PEAR packages working. -"; - - if ($php_ini = $this->getPhpiniPath()) { - print "\n\nWould you like to alter php.ini <$php_ini>? [Y/n] : "; - $alter_phpini = !stristr(fgets($this->tty, 1024), "n"); - if ($alter_phpini) { - $this->alterPhpIni($php_ini); - } else { - if (OS_WINDOWS) { - print " -Please look over your php.ini file to make sure -$this->php_dir is in your include_path."; - } else { - print " -I will add a workaround for this in the 'pear' command to make sure -the installer works, but please look over your php.ini or Apache -configuration to make sure $this->php_dir is in your include_path. -"; - } - } - } - - print " -Current include path : ".ini_get('include_path')." -Configured directory : $this->php_dir -Currently used php.ini (guess) : $php_ini -"; - - print "Press Enter to continue: "; - fgets($this->tty, 1024); - } - - $pear_cmd = $this->bin_dir . DIRECTORY_SEPARATOR . 'pear'; - $pear_cmd = OS_WINDOWS ? strtolower($pear_cmd).'.bat' : $pear_cmd; - - // check that the installed pear and the one in the path are the same (if any) - $pear_old = System::which(OS_WINDOWS ? 'pear.bat' : 'pear', $this->bin_dir); - if ($pear_old && ($pear_old != $pear_cmd)) { - // check if it is a link or symlink - $islink = OS_WINDOWS ? false : is_link($pear_old) ; - if ($islink && readlink($pear_old) != $pear_cmd) { - print "\n** WARNING! The link $pear_old does not point to the " . - "installed $pear_cmd\n"; - } elseif (!$this->localInstall && is_writable($pear_old) && !is_dir($pear_old)) { - rename($pear_old, "{$pear_old}_old"); - print "\n** WARNING! Backed up old pear to {$pear_old}_old\n"; - } else { - print "\n** WARNING! Old version found at $pear_old, please remove it or ". - "be sure to use the new $pear_cmd command\n"; - } - } - - print "\nThe 'pear' command is now at your service at $pear_cmd\n"; - - // Alert the user if the pear cmd is not in PATH - $old_dir = $pear_old ? dirname($pear_old) : false; - if (!$this->which('pear', $old_dir)) { - print " -** The 'pear' command is not currently in your PATH, so you need to -** use '$pear_cmd' until you have added -** '$this->bin_dir' to your PATH environment variable. - -"; - - print "Run it without parameters to see the available actions, try 'pear list' -to see what packages are installed, or 'pear help' for help. - -For more information about PEAR, see: - - http://pear.php.net/faq.php - http://pear.php.net/manual/ - -Thanks for using go-pear! - -"; - } - - if (OS_WINDOWS && !$this->localInstall) { - $this->win32CreateRegEnv(); - } - } - - /** - * System::which() does not allow path exclusion - */ - function which($program, $dont_search_in = false) - { - if (OS_WINDOWS) { - if ($_path = $this->safeGetEnv('Path')) { - $dirs = explode(';', $_path); - } else { - $dirs = explode(';', $this->safeGetEnv('PATH')); - } - foreach ($dirs as $i => $dir) { - $dirs[$i] = strtolower(realpath($dir)); - } - if ($dont_search_in) { - $dont_search_in = strtolower(realpath($dont_search_in)); - } - if ($dont_search_in && - ($key = array_search($dont_search_in, $dirs)) !== false) - { - unset($dirs[$key]); - } - - foreach ($dirs as $dir) { - $dir = str_replace('\\\\', '\\', $dir); - if (!strlen($dir)) { - continue; - } - if ($dir{strlen($dir) - 1} != '\\') { - $dir .= '\\'; - } - $tmp = $dir . $program; - $info = pathinfo($tmp); - if (isset($info['extension']) && in_array(strtolower($info['extension']), - array('exe', 'com', 'bat', 'cmd'))) { - if (file_exists($tmp)) { - return strtolower($tmp); - } - } elseif (file_exists($ret = $tmp . '.exe') || - file_exists($ret = $tmp . '.com') || - file_exists($ret = $tmp . '.bat') || - file_exists($ret = $tmp . '.cmd')) { - return strtolower($ret); - } - } - } else { - $dirs = explode(':', $this->safeGetEnv('PATH')); - if ($dont_search_in && - ($key = array_search($dont_search_in, $dirs)) !== false) - { - unset($dirs[$key]); - } - foreach ($dirs as $dir) { - if (is_executable("$dir/$program")) { - return "$dir/$program"; - } - } - } - return false; - } - - /** - * Not optimized, but seems to work, if some nice - * peardev will test it? :) - * - * @author Pierre-Alain Joye - */ - function alterPhpIni($pathIni='') - { - $foundAt = array(); - $iniSep = OS_WINDOWS ? ';' : ':'; - - if ($pathIni=='') { - $pathIni = $this->getPhpiniPath(); - } - - $arrayIni = file($pathIni); - $i=0; - $found=0; - - // Looks for each active include_path directives - foreach ($arrayIni as $iniLine) { - $iniLine = trim($iniLine); - $iniLine = str_replace(array("\n", "\r"), array('', ''), $iniLine); - if (preg_match("/^\s*include_path/", $iniLine)) { - $foundAt[] = $i; - $found++; - } - $i++; - } - - if ($found) { - $includeLine = $arrayIni[$foundAt[0]]; - list(, $currentPath) = explode('=', $includeLine); - - $currentPath = trim($currentPath); - if (substr($currentPath,0,1) == '"') { - $currentPath = substr($currentPath, 1, strlen($currentPath) - 2); - } - - $arrayPath = explode($iniSep, $currentPath); - $newPath = array(); - if ($arrayPath[0]=='.') { - $newPath[0] = '.'; - $newPath[1] = $this->php_dir; - array_shift($arrayPath); - } else { - $newPath[0] = $this->php_dir; - } - - foreach ($arrayPath as $path) { - $newPath[]= $path; - } - } else { - $newPath = array(); - $newPath[0] = '.'; - $newPath[1] = $this->php_dir; - $foundAt[] = count($arrayIni); // add a new line if none is present - } - $nl = OS_WINDOWS ? "\r\n" : "\n"; - $includepath = 'include_path="' . implode($iniSep,$newPath) . '"'; - $newInclude = "$nl$nl;***** Added by go-pear$nl" . - $includepath . - $nl . ";*****" . - $nl . $nl; - - $arrayIni[$foundAt[0]] = $newInclude; - - for ($i=1; $i<$found; $i++) { - $arrayIni[$foundAt[$i]]=';' . trim($arrayIni[$foundAt[$i]]); - } - - $newIni = implode("", $arrayIni); - if (!($fh = @fopen($pathIni, "wb+"))) { - $prefixIni = $this->prefix . DIRECTORY_SEPARATOR . "php.ini-gopear"; - $fh = fopen($prefixIni, "wb+"); - if (!$fh) { - echo " -****************************************************************************** -WARNING: Cannot write to $pathIni nor in $this->prefix/php.ini-gopear. Please -modify manually your php.ini by adding: - -$includepath - -"; - return false; - } else { - fwrite($fh, $newIni, strlen($newIni)); - fclose($fh); - echo " -****************************************************************************** -WARNING: Cannot write to $pathIni, but php.ini was successfully created -at <$this->prefix/php.ini-gopear>. Please replace the file <$pathIni> with -<$prefixIni> or modify your php.ini by adding: - -$includepath - -"; - - } - } else { - fwrite($fh, $newIni, strlen($newIni)); - fclose($fh); - echo " -php.ini <$pathIni> include_path updated. -"; - } - return true; - } - - /** - * Generates a registry addOn for Win32 platform - * This addon set PEAR environment variables - * @author Pierrre-Alain Joye - */ - function win32CreateRegEnv() - { - $nl = "\r\n"; - $reg ='REGEDIT4'.$nl. - '[HKEY_CURRENT_USER\Environment]'. $nl . - '"PHP_PEAR_SYSCONF_DIR"="' . addslashes($this->prefix) . '"' . $nl . - '"PHP_PEAR_INSTALL_DIR"="' . addslashes($this->php_dir) . '"' . $nl . - '"PHP_PEAR_DOC_DIR"="' . addslashes($this->doc_dir) . '"' . $nl . - '"PHP_PEAR_BIN_DIR"="' . addslashes($this->bin_dir) . '"' . $nl . - '"PHP_PEAR_DATA_DIR"="' . addslashes($this->data_dir) . '"' . $nl . - '"PHP_PEAR_PHP_BIN"="' . addslashes($this->php_bin) . '"' . $nl . - '"PHP_PEAR_TEST_DIR"="' . addslashes($this->test_dir) . '"' . $nl; - - $fh = fopen($this->prefix . DIRECTORY_SEPARATOR . 'PEAR_ENV.reg', 'wb'); - if($fh){ - fwrite($fh, $reg, strlen($reg)); - fclose($fh); - echo " - -* WINDOWS ENVIRONMENT VARIABLES * -For convenience, a REG file is available under $this->prefix\\PEAR_ENV.reg . -This file creates ENV variables for the current user. - -Double-click this file to add it to the current user registry. - -"; - } - } - - function displayHTMLProgress() - { - } -} -?> - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/**#@+ - * Error codes for task validation routines - */ -define('PEAR_TASK_ERROR_NOATTRIBS', 1); -define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2); -define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3); -define('PEAR_TASK_ERROR_INVALID', 4); -/**#@-*/ -define('PEAR_TASK_PACKAGE', 1); -define('PEAR_TASK_INSTALL', 2); -define('PEAR_TASK_PACKAGEANDINSTALL', 3); -/** - * A task is an operation that manipulates the contents of a file. - * - * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been - * processed and installed, and are designed to operate on all files containing the task. - * The Post-install script task simply takes advantage of the fact that it will be run - * after installation, replace is a simple task. - * - * Combining tasks is possible, but ordering is significant. - * - * - * - * - * - * - * This will first replace any instance of @data-dir@ in the test.php file - * with the path to the current data directory. Then, it will include the - * test.php file and run the script it contains to configure the package post-installation. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - * @abstract - */ -class PEAR_Task_Common -{ - /** - * Valid types for this version are 'simple' and 'multiple' - * - * - simple tasks operate on the contents of a file and write out changes to disk - * - multiple tasks operate on the contents of many files and write out the - * changes directly to disk - * - * Child task classes must override this property. - * @access protected - */ - var $type = 'simple'; - /** - * Determines which install phase this task is executed under - */ - var $phase = PEAR_TASK_INSTALL; - /** - * @access protected - */ - var $config; - /** - * @access protected - */ - var $registry; - /** - * @access protected - */ - var $logger; - /** - * @access protected - */ - var $installphase; - /** - * @param PEAR_Config - * @param PEAR_Common - */ - function PEAR_Task_Common(&$config, &$logger, $phase) - { - $this->config = &$config; - $this->registry = &$config->getRegistry(); - $this->logger = &$logger; - $this->installphase = $phase; - if ($this->type == 'multiple') { - $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this; - } - } - - /** - * Validate the basic contents of a task tag. - * @param PEAR_PackageFile_v2 - * @param array - * @param PEAR_Config - * @param array the entire parsed tag - * @return true|array On error, return an array in format: - * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...]) - * - * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in - * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array - * of legal values in - * @static - * @abstract - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param array attributes from the tag containing this task - * @param string|null last installed version of this package - * @abstract - */ - function init($xml, $fileAttributes, $lastVersion) - { - } - - /** - * Begin a task processing session. All multiple tasks will be processed after each file - * has been successfully installed, all simple tasks should perform their task here and - * return any errors using the custom throwError() method to allow forward compatibility - * - * This method MUST NOT write out any changes to disk - * @param PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - * @abstract - */ - function startSession($pkg, $contents, $dest) - { - } - - /** - * This method is used to process each of the tasks for a particular multiple class - * type. Simple tasks need not implement this method. - * @param array an array of tasks - * @access protected - * @static - * @abstract - */ - function run($tasks) - { - } - - /** - * @static - * @final - */ - function hasPostinstallTasks() - { - return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); - } - - /** - * @static - * @final - */ - function runPostinstallTasks() - { - foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) { - $err = call_user_func(array($class, 'run'), - $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]); - if ($err) { - return PEAR_Task_Common::throwError($err); - } - } - unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); - } - - /** - * Determines whether a role is a script - * @return bool - */ - function isScript() - { - return $this->type == 'script'; - } - - function throwError($msg, $code = -1) - { - include_once 'phar://go-pear.phar/' . 'PEAR.php'; - return PEAR::raiseError($msg, $code); - } -} -?> - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Postinstallscript.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php'; -/** - * Implements the postinstallscript file task. - * - * Note that post-install scripts are handled separately from installation, by the - * "pear run-scripts" command - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Postinstallscript extends PEAR_Task_Common -{ - var $type = 'script'; - var $_class; - var $_params; - var $_obj; - /** - * - * @var PEAR_PackageFile_v2 - */ - var $_pkg; - var $_contents; - var $phase = PEAR_TASK_INSTALL; - - /** - * Validate the raw xml at parsing-time. - * - * This also attempts to validate the script to make sure it meets the criteria - * for a post-install script - * @param PEAR_PackageFile_v2 - * @param array The XML contents of the tag - * @param PEAR_Config - * @param array the entire parsed tag - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($fileXml['role'] != 'php') { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must be role="php"'); - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $file = $pkg->getFileContents($fileXml['name']); - if (PEAR::isError($file)) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" is not valid: ' . - $file->getMessage()); - } elseif ($file === null) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" could not be retrieved for processing!'); - } else { - $analysis = $pkg->analyzeSourceCode($file, true); - if (!$analysis) { - PEAR::popErrorHandling(); - $warnings = ''; - foreach ($pkg->getValidationWarnings() as $warn) { - $warnings .= $warn['message'] . "\n"; - } - return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' . - $fileXml['name'] . '" failed: ' . $warnings); - } - if (count($analysis['declared_classes']) != 1) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare exactly 1 class'); - } - $class = $analysis['declared_classes'][0]; - if ($class != str_replace(array('/', '.php'), array('_', ''), - $fileXml['name']) . '_postinstall') { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" class "' . $class . '" must be named "' . - str_replace(array('/', '.php'), array('_', ''), - $fileXml['name']) . '_postinstall"'); - } - if (!isset($analysis['declared_methods'][$class])) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare methods init() and run()'); - } - $methods = array('init' => 0, 'run' => 1); - foreach ($analysis['declared_methods'][$class] as $method) { - if (isset($methods[$method])) { - unset($methods[$method]); - } - } - if (count($methods)) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare methods init() and run()'); - } - } - PEAR::popErrorHandling(); - $definedparams = array(); - $tasksNamespace = $pkg->getTasksNs() . ':'; - if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) { - // in order to support the older betas, which did not expect internal tags - // to also use the namespace - $tasksNamespace = ''; - } - if (isset($xml[$tasksNamespace . 'paramgroup'])) { - $params = $xml[$tasksNamespace . 'paramgroup']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); - } - foreach ($params as $param) { - if (!isset($param[$tasksNamespace . 'id'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must have ' . - 'an ' . $tasksNamespace . 'id> tag'); - } - if (isset($param[$tasksNamespace . 'name'])) { - if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" parameter "' . $param[$tasksNamespace . 'name'] . - '" has not been previously defined'); - } - if (!isset($param[$tasksNamespace . 'conditiontype'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'conditiontype> tag containing either "=", ' . - '"!=", or "preg_match"'); - } - if (!in_array($param[$tasksNamespace . 'conditiontype'], - array('=', '!=', 'preg_match'))) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'conditiontype> tag containing either "=", ' . - '"!=", or "preg_match"'); - } - if (!isset($param[$tasksNamespace . 'value'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'value> tag containing expected parameter value'); - } - } - if (isset($param[$tasksNamespace . 'instructions'])) { - if (!is_string($param[$tasksNamespace . 'instructions'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" ' . $tasksNamespace . 'instructions> must be simple text'); - } - } - if (!isset($param[$tasksNamespace . 'param'])) { - continue; // is no longer required - } - $subparams = $param[$tasksNamespace . 'param']; - if (!is_array($subparams) || !isset($subparams[0])) { - $subparams = array($subparams); - } - foreach ($subparams as $subparam) { - if (!isset($subparam[$tasksNamespace . 'name'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter for ' . - $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . '" must have ' . - 'a ' . $tasksNamespace . 'name> tag'); - } - if (!preg_match('/[a-zA-Z0-9]+/', - $subparam[$tasksNamespace . 'name'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" is not a valid name. Must contain only alphanumeric characters'); - } - if (!isset($subparam[$tasksNamespace . 'prompt'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . 'prompt> tag'); - } - if (!isset($subparam[$tasksNamespace . 'type'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . 'type> tag'); - } - $definedparams[] = $param[$tasksNamespace . 'id'] . '::' . - $subparam[$tasksNamespace . 'name']; - } - } - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param array attributes from the tag containing this task - * @param string|null last installed version of this package, if any (useful for upgrades) - */ - function init($xml, $fileattribs, $lastversion) - { - $this->_class = str_replace('/', '_', $fileattribs['name']); - $this->_filename = $fileattribs['name']; - $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall'; - $this->_params = $xml; - $this->_lastversion = $lastversion; - } - - /** - * Strip the tasks: namespace from internal params - * - * @access private - */ - function _stripNamespace($params = null) - { - if ($params === null) { - $params = array(); - if (!is_array($this->_params)) { - return; - } - foreach ($this->_params as $i => $param) { - if (is_array($param)) { - $param = $this->_stripNamespace($param); - } - $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; - } - $this->_params = $params; - } else { - $newparams = array(); - foreach ($params as $i => $param) { - if (is_array($param)) { - $param = $this->_stripNamespace($param); - } - $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; - } - return $newparams; - } - } - - /** - * Unlike other tasks, the installed file name is passed in instead of the file contents, - * because this task is handled post-installation - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file name - * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError) - */ - function startSession($pkg, $contents) - { - if ($this->installphase != PEAR_TASK_INSTALL) { - return false; - } - // remove the tasks: namespace if present - $this->_pkg = $pkg; - $this->_stripNamespace(); - $this->logger->log(0, 'Including external post-installation script "' . - $contents . '" - any errors are in this script'); - include_once 'phar://go-pear.phar/' . $contents; - if (class_exists($this->_class)) { - $this->logger->log(0, 'Inclusion succeeded'); - } else { - return $this->throwError('init of post-install script class "' . $this->_class - . '" failed'); - } - $this->_obj = new $this->_class; - $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $res = $this->_obj->init($this->config, $pkg, $this->_lastversion); - PEAR::popErrorHandling(); - if ($res) { - $this->logger->log(0, 'init succeeded'); - } else { - return $this->throwError('init of post-install script "' . $this->_class . - '->init()" failed'); - } - $this->_contents = $contents; - return true; - } - - /** - * No longer used - * @see PEAR_PackageFile_v2::runPostinstallScripts() - * @param array an array of tasks - * @param string install or upgrade - * @access protected - * @static - */ - function run() - { - } -} -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Postinstallscript.php'; -/** - * Abstracts the postinstallscript file task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript -{ - /** - * parent package file object - * - * @var PEAR_PackageFile_v2_rw - */ - var $_pkg; - /** - * Enter description here... - * - * @param PEAR_PackageFile_v2_rw $pkg - * @param PEAR_Config $config - * @param PEAR_Frontend $logger - * @param array $fileXml - * @return PEAR_Task_Postinstallscript_rw - */ - function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); - } - - function getName() - { - return 'postinstallscript'; - } - - /** - * add a simple to the post-install script - * - * Order is significant, so call this method in the same - * sequence the users should see the paramgroups. The $params - * parameter should either be the result of a call to {@link getParam()} - * or an array of calls to getParam(). - * - * Use {@link addConditionTypeGroup()} to add a containing - * a tag - * @param string $id id as seen by the script - * @param array|false $params array of getParam() calls, or false for no params - * @param string|false $instructions - */ - function addParamGroup($id, $params = false, $instructions = false) - { - if ($params && isset($params[0]) && !isset($params[1])) { - $params = $params[0]; - } - $stuff = - array( - $this->_pkg->getTasksNs() . ':id' => $id, - ); - if ($instructions) { - $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; - } - if ($params) { - $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; - } - $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; - } - - /** - * add a complex to the post-install script with conditions - * - * This inserts a with - * - * Order is significant, so call this method in the same - * sequence the users should see the paramgroups. The $params - * parameter should either be the result of a call to {@link getParam()} - * or an array of calls to getParam(). - * - * Use {@link addParamGroup()} to add a simple - * - * @param string $id id as seen by the script - * @param string $oldgroup id of the section referenced by - * - * @param string $param name of the from the older section referenced - * by - * @param string $value value to match of the parameter - * @param string $conditiontype one of '=', '!=', 'preg_match' - * @param array|false $params array of getParam() calls, or false for no params - * @param string|false $instructions - */ - function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=', - $params = false, $instructions = false) - { - if ($params && isset($params[0]) && !isset($params[1])) { - $params = $params[0]; - } - $stuff = array( - $this->_pkg->getTasksNs() . ':id' => $id, - ); - if ($instructions) { - $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; - } - $stuff[$this->_pkg->getTasksNs() . ':name'] = $oldgroup . '::' . $param; - $stuff[$this->_pkg->getTasksNs() . ':conditiontype'] = $conditiontype; - $stuff[$this->_pkg->getTasksNs() . ':value'] = $value; - if ($params) { - $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; - } - $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; - } - - function getXml() - { - return $this->_params; - } - - /** - * Use to set up a param tag for use in creating a paramgroup - * @static - */ - function getParam($name, $prompt, $type = 'string', $default = null) - { - if ($default !== null) { - return - array( - $this->_pkg->getTasksNs() . ':name' => $name, - $this->_pkg->getTasksNs() . ':prompt' => $prompt, - $this->_pkg->getTasksNs() . ':type' => $type, - $this->_pkg->getTasksNs() . ':default' => $default - ); - } - return - array( - $this->_pkg->getTasksNs() . ':name' => $name, - $this->_pkg->getTasksNs() . ':prompt' => $prompt, - $this->_pkg->getTasksNs() . ':type' => $type, - ); - } -} -?> - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Replace.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php'; -/** - * Implements the replace file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Replace extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGEANDINSTALL; - var $_replacements; - - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if (!isset($xml['attribs'])) { - return array(PEAR_TASK_ERROR_NOATTRIBS); - } - if (!isset($xml['attribs']['type'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type'); - } - if (!isset($xml['attribs']['to'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to'); - } - if (!isset($xml['attribs']['from'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from'); - } - if ($xml['attribs']['type'] == 'pear-config') { - if (!in_array($xml['attribs']['to'], $config->getKeys())) { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - $config->getKeys()); - } - } elseif ($xml['attribs']['type'] == 'php-const') { - if (defined($xml['attribs']['to'])) { - return true; - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - array('valid PHP constant')); - } - } elseif ($xml['attribs']['type'] == 'package-info') { - if (in_array($xml['attribs']['to'], - array('name', 'summary', 'channel', 'notes', 'extends', 'description', - 'release_notes', 'license', 'release-license', 'license-uri', - 'version', 'api-version', 'state', 'api-state', 'release_date', - 'date', 'time'))) { - return true; - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - array('name', 'summary', 'channel', 'notes', 'extends', 'description', - 'release_notes', 'license', 'release-license', 'license-uri', - 'version', 'api-version', 'state', 'api-state', 'release_date', - 'date', 'time')); - } - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'], - array('pear-config', 'package-info', 'php-const')); - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) - { - $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml; - } - - /** - * Do a package.xml 1.0 replacement, with additional package-info fields available - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) - { - $subst_from = $subst_to = array(); - foreach ($this->_replacements as $a) { - $a = $a['attribs']; - $to = ''; - if ($a['type'] == 'pear-config') { - if ($this->installphase == PEAR_TASK_PACKAGE) { - return false; - } - if ($a['to'] == 'master_server') { - $chan = $this->registry->getChannel($pkg->getChannel()); - if (!PEAR::isError($chan)) { - $to = $chan->getServer(); - } else { - $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); - return false; - } - } else { - if ($this->config->isDefinedLayer('ftp')) { - // try the remote config file first - $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel()); - if (is_null($to)) { - // then default to local - $to = $this->config->get($a['to'], null, $pkg->getChannel()); - } - } else { - $to = $this->config->get($a['to'], null, $pkg->getChannel()); - } - } - if (is_null($to)) { - $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); - return false; - } - } elseif ($a['type'] == 'php-const') { - if ($this->installphase == PEAR_TASK_PACKAGE) { - return false; - } - if (defined($a['to'])) { - $to = constant($a['to']); - } else { - $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]"); - return false; - } - } else { - if ($t = $pkg->packageInfo($a['to'])) { - $to = $t; - } else { - $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]"); - return false; - } - } - if (!is_null($to)) { - $subst_from[] = $a['from']; - $subst_to[] = $to; - } - } - $this->logger->log(3, "doing " . sizeof($subst_from) . - " substitution(s) for $dest"); - if (sizeof($subst_from)) { - $contents = str_replace($subst_from, $subst_to, $contents); - } - return $contents; - } -} -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Replace.php'; -/** - * Abstracts the replace task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Replace_rw extends PEAR_Task_Replace -{ - function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); - } - - function setInfo($from, $to, $type) - { - $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); - } - - function getName() - { - return 'replace'; - } - - function getXml() - { - return $this->_params; - } -} -?> - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Unixeol.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php'; -/** - * Implements the unix line endings file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Unixeol extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGE; - var $_replacements; - - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($xml != '') { - return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) - { - } - - /** - * Replace all line endings with line endings customized for the current OS - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) - { - $this->logger->log(3, "replacing all line endings with \\n in $dest"); - return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); - } -} -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Unixeol.php'; -/** - * Abstracts the unixeol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol -{ - function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'unixeol'; - } - - function getXml() - { - return ''; - } -} -?> - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Windowseol.php 276394 2009-02-25 00:15:49Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php'; -/** - * Implements the windows line endsings file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Windowseol extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGE; - var $_replacements; - - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($xml != '') { - return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); - } - return true; - } - - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) - { - } - - /** - * Replace all line endings with windows line endings - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) - { - $this->logger->log(3, "replacing all line endings with \\r\\n in $dest"); - return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); - } -} -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Task/Windowseol.php'; -/** - * Abstracts the windowseol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol -{ - function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'windowseol'; - } - - function getXml() - { - return ''; - } -} -?> - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validate.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/**#@+ - * Constants for install stage - */ -define('PEAR_VALIDATE_INSTALLING', 1); -define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others -define('PEAR_VALIDATE_NORMAL', 3); -define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others -define('PEAR_VALIDATE_PACKAGING', 7); -/**#@-*/ -require_once 'phar://go-pear.phar/' . 'PEAR/Common.php'; -require_once 'phar://go-pear.phar/' . 'PEAR/Validator/PECL.php'; - -/** - * Validation class for package.xml - channel-level advanced validation - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Validate -{ - var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG; - /** - * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - var $_packagexml; - /** - * @var int one of the PEAR_VALIDATE_* constants - */ - var $_state = PEAR_VALIDATE_NORMAL; - /** - * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same) - * @var array - * @access private - */ - var $_failures = array('error' => array(), 'warning' => array()); - - /** - * Override this method to handle validation of normal package names - * @param string - * @return bool - * @access protected - */ - function _validPackageName($name) - { - return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name); - } - - /** - * @param string package name to validate - * @param string name of channel-specific validation package - * @final - */ - function validPackageName($name, $validatepackagename = false) - { - if ($validatepackagename) { - if (strtolower($name) == strtolower($validatepackagename)) { - return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name); - } - } - return $this->_validPackageName($name); - } - - /** - * This validates a bundle name, and bundle names must conform - * to the PEAR naming convention, so the method is final and static. - * @param string - * @final - * @static - */ - function validGroupName($name) - { - return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name); - } - - /** - * Determine whether $state represents a valid stability level - * @param string - * @return bool - * @static - * @final - */ - function validState($state) - { - return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable')); - } - - /** - * Get a list of valid stability levels - * @return array - * @static - * @final - */ - function getValidStates() - { - return array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - } - - /** - * Determine whether a version is a properly formatted version number that can be used - * by version_compare - * @param string - * @return bool - * @static - * @final - */ - function validVersion($ver) - { - return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function setPackageFile(&$pf) - { - $this->_packagexml = &$pf; - } - - /** - * @access private - */ - function _addFailure($field, $reason) - { - $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason); - } - - /** - * @access private - */ - function _addWarning($field, $reason) - { - $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason); - } - - function getFailures() - { - $failures = $this->_failures; - $this->_failures = array('warnings' => array(), 'errors' => array()); - return $failures; - } - - /** - * @param int one of the PEAR_VALIDATE_* constants - */ - function validate($state = null) - { - if (!isset($this->_packagexml)) { - return false; - } - if ($state !== null) { - $this->_state = $state; - } - $this->_failures = array('warnings' => array(), 'errors' => array()); - $this->validatePackageName(); - $this->validateVersion(); - $this->validateMaintainers(); - $this->validateDate(); - $this->validateSummary(); - $this->validateDescription(); - $this->validateLicense(); - $this->validateNotes(); - if ($this->_packagexml->getPackagexmlVersion() == '1.0') { - $this->validateState(); - $this->validateFilelist(); - } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' || - $this->_packagexml->getPackagexmlVersion() == '2.1') { - $this->validateTime(); - $this->validateStability(); - $this->validateDeps(); - $this->validateMainFilelist(); - $this->validateReleaseFilelist(); - //$this->validateGlobalTasks(); - $this->validateChangelog(); - } - return !((bool) count($this->_failures['errors'])); - } - - /** - * @access protected - */ - function validatePackageName() - { - if ($this->_state == PEAR_VALIDATE_PACKAGING || - $this->_state == PEAR_VALIDATE_NORMAL) { - if (($this->_packagexml->getPackagexmlVersion() == '2.0' || - $this->_packagexml->getPackagexmlVersion() == '2.1') && - $this->_packagexml->getExtends()) { - $version = $this->_packagexml->getVersion() . ''; - $name = $this->_packagexml->getPackage(); - $test = array_shift($a = explode('.', $version)); - if ($test == '0') { - return true; - } - $vlen = strlen($test); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if ($majver != $test) { - $this->_addWarning('package', "package $name extends package " . - $this->_packagexml->getExtends() . ' and so the name should ' . - 'have a postfix equal to the major version like "' . - $this->_packagexml->getExtends() . $test . '"'); - return true; - } elseif (substr($name, 0, strlen($name) - $vlen) != - $this->_packagexml->getExtends()) { - $this->_addWarning('package', "package $name extends package " . - $this->_packagexml->getExtends() . ' and so the name must ' . - 'be an extension like "' . $this->_packagexml->getExtends() . - $test . '"'); - return true; - } - } - } - if (!$this->validPackageName($this->_packagexml->getPackage())) { - $this->_addFailure('name', 'package name "' . - $this->_packagexml->getPackage() . '" is invalid'); - return false; - } - } - - /** - * @access protected - */ - function validateVersion() - { - if ($this->_state != PEAR_VALIDATE_PACKAGING) { - if (!$this->validVersion($this->_packagexml->getVersion())) { - $this->_addFailure('version', - 'Invalid version number "' . $this->_packagexml->getVersion() . '"'); - } - return false; - } - $version = $this->_packagexml->getVersion(); - $versioncomponents = explode('.', $version); - if (count($versioncomponents) != 3) { - $this->_addWarning('version', - 'A version number should have 3 decimals (x.y.z)'); - return true; - } - $name = $this->_packagexml->getPackage(); - // version must be based upon state - switch ($this->_packagexml->getState()) { - case 'snapshot' : - return true; - case 'devel' : - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } else { - $this->_addWarning('version', - 'packages with devel stability must be < version 1.0.0'); - } - return true; - break; - case 'alpha' : - case 'beta' : - // check for a package that extends a package, - // like Foo and Foo2 - if ($this->_state == PEAR_VALIDATE_PACKAGING) { - if (substr($versioncomponents[2], 1, 2) == 'rc') { - $this->_addFailure('version', 'Release Candidate versions ' . - 'must have capital RC, not lower-case rc'); - return false; - } - } - if (!$this->_packagexml->getExtends()) { - if ($versioncomponents[0] == '1') { - if ($versioncomponents[2]{0} == '0') { - if ($versioncomponents[2] == '0') { - // version 1.*.0000 - $this->_addWarning('version', - 'version 1.' . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return true; - } elseif (strlen($versioncomponents[2]) > 1) { - // version 1.*.0RC1 or 1.*.0beta24 etc. - return true; - } else { - // version 1.*.0 - $this->_addWarning('version', - 'version 1.' . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return true; - } - } else { - $this->_addWarning('version', - 'bugfix versions (1.3.x where x > 0) probably should ' . - 'not be alpha or beta'); - return true; - } - } elseif ($versioncomponents[0] != '0') { - $this->_addWarning('version', - 'major versions greater than 1 are not allowed for packages ' . - 'without an tag or an identical postfix (foo2 v2.0.0)'); - return true; - } - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } - } else { - $vlen = strlen($versioncomponents[0] . ''); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { - $this->_addWarning('version', 'first version number "' . - $versioncomponents[0] . '" must match the postfix of ' . - 'package name "' . $name . '" (' . - $majver . ')'); - return true; - } - if ($versioncomponents[0] == $majver) { - if ($versioncomponents[2]{0} == '0') { - if ($versioncomponents[2] == '0') { - // version 2.*.0000 - $this->_addWarning('version', - "version $majver." . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return false; - } elseif (strlen($versioncomponents[2]) > 1) { - // version 2.*.0RC1 or 2.*.0beta24 etc. - return true; - } else { - // version 2.*.0 - $this->_addWarning('version', - "version $majver." . $versioncomponents[1] . - '.0 cannot be alpha or beta'); - return true; - } - } else { - $this->_addWarning('version', - "bugfix versions ($majver.x.y where y > 0) should " . - 'not be alpha or beta'); - return true; - } - } elseif ($versioncomponents[0] != '0') { - $this->_addWarning('version', - "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases"); - return true; - } - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } - } - return true; - break; - case 'stable' : - if ($versioncomponents[0] == '0') { - $this->_addWarning('version', 'versions less than 1.0.0 cannot ' . - 'be stable'); - return true; - } - if (!is_numeric($versioncomponents[2])) { - if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i', - $versioncomponents[2])) { - $this->_addWarning('version', 'version "' . $version . '" or any ' . - 'RC/beta/alpha version cannot be stable'); - return true; - } - } - // check for a package that extends a package, - // like Foo and Foo2 - if ($this->_packagexml->getExtends()) { - $vlen = strlen($versioncomponents[0] . ''); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { - $this->_addWarning('version', 'first version number "' . - $versioncomponents[0] . '" must match the postfix of ' . - 'package name "' . $name . '" (' . - $majver . ')'); - return true; - } - } elseif ($versioncomponents[0] > 1) { - $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' . - '1 for any package that does not have an tag'); - } - return true; - break; - default : - return false; - break; - } - } - - /** - * @access protected - */ - function validateMaintainers() - { - // maintainers can only be truly validated server-side for most channels - // but allow this customization for those who wish it - return true; - } - - /** - * @access protected - */ - function validateDate() - { - if ($this->_state == PEAR_VALIDATE_NORMAL || - $this->_state == PEAR_VALIDATE_PACKAGING) { - - if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/', - $this->_packagexml->getDate(), $res) || - count($res) < 4 - || !checkdate($res[2], $res[3], $res[1]) - ) { - $this->_addFailure('date', 'invalid release date "' . - $this->_packagexml->getDate() . '"'); - return false; - } - - if ($this->_state == PEAR_VALIDATE_PACKAGING && - $this->_packagexml->getDate() != date('Y-m-d')) { - $this->_addWarning('date', 'Release Date "' . - $this->_packagexml->getDate() . '" is not today'); - } - } - return true; - } - - /** - * @access protected - */ - function validateTime() - { - if (!$this->_packagexml->getTime()) { - // default of no time value set - return true; - } - - // packager automatically sets time, so only validate if pear validate is called - if ($this->_state = PEAR_VALIDATE_NORMAL) { - if (!preg_match('/\d\d:\d\d:\d\d/', - $this->_packagexml->getTime())) { - $this->_addFailure('time', 'invalid release time "' . - $this->_packagexml->getTime() . '"'); - return false; - } - - $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches); - if ($result === false || empty($matches)) { - $this->_addFailure('time', 'invalid release time "' . - $this->_packagexml->getTime() . '"'); - return false; - } - } - - return true; - } - - /** - * @access protected - */ - function validateState() - { - // this is the closest to "final" php4 can get - if (!PEAR_Validate::validState($this->_packagexml->getState())) { - if (strtolower($this->_packagexml->getState() == 'rc')) { - $this->_addFailure('state', 'RC is not a state, it is a version ' . - 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta'); - } - $this->_addFailure('state', 'invalid release state "' . - $this->_packagexml->getState() . '", must be one of: ' . - implode(', ', PEAR_Validate::getValidStates())); - return false; - } - return true; - } - - /** - * @access protected - */ - function validateStability() - { - $ret = true; - $packagestability = $this->_packagexml->getState(); - $apistability = $this->_packagexml->getState('api'); - if (!PEAR_Validate::validState($packagestability)) { - $this->_addFailure('state', 'invalid release stability "' . - $this->_packagexml->getState() . '", must be one of: ' . - implode(', ', PEAR_Validate::getValidStates())); - $ret = false; - } - $apistates = PEAR_Validate::getValidStates(); - array_shift($apistates); // snapshot is not allowed - if (!in_array($apistability, $apistates)) { - $this->_addFailure('state', 'invalid API stability "' . - $this->_packagexml->getState('api') . '", must be one of: ' . - implode(', ', $apistates)); - $ret = false; - } - return $ret; - } - - /** - * @access protected - */ - function validateSummary() - { - return true; - } - - /** - * @access protected - */ - function validateDescription() - { - return true; - } - - /** - * @access protected - */ - function validateLicense() - { - return true; - } - - /** - * @access protected - */ - function validateNotes() - { - return true; - } - - /** - * for package.xml 2.0 only - channels can't use package.xml 1.0 - * @access protected - */ - function validateDependencies() - { - return true; - } - - /** - * for package.xml 1.0 only - * @access private - */ - function _validateFilelist() - { - return true; // placeholder for now - } - - /** - * for package.xml 2.0 only - * @access protected - */ - function validateMainFilelist() - { - return true; // placeholder for now - } - - /** - * for package.xml 2.0 only - * @access protected - */ - function validateReleaseFilelist() - { - return true; // placeholder for now - } - - /** - * @access protected - */ - function validateChangelog() - { - return true; - } - - /** - * @access protected - */ - function validateFilelist() - { - return true; - } - - /** - * @access protected - */ - function validateDeps() - { - return true; - } -} - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PECL.php 276383 2009-02-24 23:39:37Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a5 - */ -/** - * This is the parent class for all validators - */ -require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php'; -/** - * Channel Validator for the pecl.php.net channel - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a5 - */ -class PEAR_Validator_PECL extends PEAR_Validate -{ - function validateVersion() - { - if ($this->_state == PEAR_VALIDATE_PACKAGING) { - $version = $this->_packagexml->getVersion(); - $versioncomponents = explode('.', $version); - $last = array_pop($versioncomponents); - if (substr($last, 1, 2) == 'rc') { - $this->_addFailure('version', 'Release Candidate versions must have ' . - 'upper-case RC, not lower-case rc'); - return false; - } - } - return true; - } - - function validatePackageName() - { - $ret = parent::validatePackageName(); - if ($this->_packagexml->getPackageType() == 'extsrc' || - $this->_packagexml->getPackageType() == 'zendextsrc') { - if (strtolower($this->_packagexml->getPackage()) != - strtolower($this->_packagexml->getProvidesExtension())) { - $this->_addWarning('providesextension', 'package name "' . - $this->_packagexml->getPackage() . '" is different from extension name "' . - $this->_packagexml->getProvidesExtension() . '"'); - } - } - return $ret; - } -} -?> - * @author Stephan Schmidt (original XML_Unserializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: XMLParser.php 282970 2009-06-28 23:10:07Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Parser for any xml file - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stephan Schmidt (original XML_Unserializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version Release: 1.9.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_XMLParser -{ - /** - * unserilialized data - * @var string $_serializedData - */ - var $_unserializedData = null; - - /** - * name of the root tag - * @var string $_root - */ - var $_root = null; - - /** - * stack for all data that is found - * @var array $_dataStack - */ - var $_dataStack = array(); - - /** - * stack for all values that are generated - * @var array $_valStack - */ - var $_valStack = array(); - - /** - * current tag depth - * @var int $_depth - */ - var $_depth = 0; - - /** - * The XML encoding to use - * @var string $encoding - */ - var $encoding = 'ISO-8859-1'; - - /** - * @return array - */ - function getData() - { - return $this->_unserializedData; - } - - /** - * @param string xml content - * @return true|PEAR_Error - */ - function parse($data) - { - if (!extension_loaded('xml')) { - include_once 'phar://go-pear.phar/' . 'PEAR.php'; - return PEAR::raiseError("XML Extension not found", 1); - } - $this->_dataStack = $this->_valStack = array(); - $this->_depth = 0; - - if ( - strpos($data, 'encoding="UTF-8"') - || strpos($data, 'encoding="utf-8"') - || strpos($data, "encoding='UTF-8'") - || strpos($data, "encoding='utf-8'") - ) { - $this->encoding = 'UTF-8'; - } - - if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') { - $data = utf8_decode($data); - $this->encoding = 'ISO-8859-1'; - } - - $xp = xml_parser_create($this->encoding); - xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0); - xml_set_object($xp, $this); - xml_set_element_handler($xp, 'startHandler', 'endHandler'); - xml_set_character_data_handler($xp, 'cdataHandler'); - if (!xml_parse($xp, $data)) { - $msg = xml_error_string(xml_get_error_code($xp)); - $line = xml_get_current_line_number($xp); - xml_parser_free($xp); - include_once 'phar://go-pear.phar/' . 'PEAR.php'; - return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2); - } - xml_parser_free($xp); - return true; - } - - /** - * Start element handler for XML parser - * - * @access private - * @param object $parser XML parser object - * @param string $element XML element - * @param array $attribs attributes of XML tag - * @return void - */ - function startHandler($parser, $element, $attribs) - { - $this->_depth++; - $this->_dataStack[$this->_depth] = null; - - $val = array( - 'name' => $element, - 'value' => null, - 'type' => 'string', - 'childrenKeys' => array(), - 'aggregKeys' => array() - ); - - if (count($attribs) > 0) { - $val['children'] = array(); - $val['type'] = 'array'; - $val['children']['attribs'] = $attribs; - } - - array_push($this->_valStack, $val); - } - - /** - * post-process data - * - * @param string $data - * @param string $element element name - */ - function postProcess($data, $element) - { - return trim($data); - } - - /** - * End element handler for XML parser - * - * @access private - * @param object XML parser object - * @param string - * @return void - */ - function endHandler($parser, $element) - { - $value = array_pop($this->_valStack); - $data = $this->postProcess($this->_dataStack[$this->_depth], $element); - - // adjust type of the value - switch (strtolower($value['type'])) { - // unserialize an array - case 'array': - if ($data !== '') { - $value['children']['_content'] = $data; - } - - $value['value'] = isset($value['children']) ? $value['children'] : array(); - break; - - /* - * unserialize a null value - */ - case 'null': - $data = null; - break; - - /* - * unserialize any scalar value - */ - default: - settype($data, $value['type']); - $value['value'] = $data; - break; - } - - $parent = array_pop($this->_valStack); - if ($parent === null) { - $this->_unserializedData = &$value['value']; - $this->_root = &$value['name']; - return true; - } - - // parent has to be an array - if (!isset($parent['children']) || !is_array($parent['children'])) { - $parent['children'] = array(); - if ($parent['type'] != 'array') { - $parent['type'] = 'array'; - } - } - - if (!empty($value['name'])) { - // there already has been a tag with this name - if (in_array($value['name'], $parent['childrenKeys'])) { - // no aggregate has been created for this tag - if (!in_array($value['name'], $parent['aggregKeys'])) { - if (isset($parent['children'][$value['name']])) { - $parent['children'][$value['name']] = array($parent['children'][$value['name']]); - } else { - $parent['children'][$value['name']] = array(); - } - array_push($parent['aggregKeys'], $value['name']); - } - array_push($parent['children'][$value['name']], $value['value']); - } else { - $parent['children'][$value['name']] = &$value['value']; - array_push($parent['childrenKeys'], $value['name']); - } - } else { - array_push($parent['children'],$value['value']); - } - array_push($this->_valStack, $parent); - - $this->_depth--; - } - - /** - * Handler for character data - * - * @access private - * @param object XML parser object - * @param string CDATA - * @return void - */ - function cdataHandler($parser, $cdata) - { - $this->_dataStack[$this->_depth] .= $cdata; - } -} | -// +-----------------------------------------------------------------------------+ -// -/** - * The Graph.php file contains the definition of the Structures_Graph class - * - * @see Structures_Graph - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** PEAR base classes */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -/** Graph Node */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php'; -/* }}} */ - -define('STRUCTURES_GRAPH_ERROR_GENERIC', 100); - -/* class Structures_Graph {{{ */ -/** - * The Structures_Graph class represents a graph data structure. - * - * A Graph is a data structure composed by a set of nodes, connected by arcs. - * Graphs may either be directed or undirected. In a directed graph, arcs are - * directional, and can be traveled only one way. In an undirected graph, arcs - * are bidirectional, and can be traveled both ways. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @package Structures_Graph - */ -/* }}} */ -class Structures_Graph { - /* fields {{{ */ - /** - * @access private - */ - var $_nodes = array(); - /** - * @access private - */ - var $_directed = false; - /* }}} */ - - /* Constructor {{{ */ - /** - * - * Constructor - * - * @param boolean Set to true if the graph is directed. Set to false if it is not directed. (Optional, defaults to true) - * @access public - */ - function Structures_Graph($directed = true) { - $this->_directed = $directed; - } - /* }}} */ - - /* isDirected {{{ */ - /** - * - * Return true if a graph is directed - * - * @return boolean true if the graph is directed - * @access public - */ - function isDirected() { - return (boolean) $this->_directed; - } - /* }}} */ - - /* addNode {{{ */ - /** - * - * Add a Node to the Graph - * - * @param Structures_Graph_Node The node to be added. - * @access public - */ - function addNode(&$newNode) { - // We only add nodes - if (!is_a($newNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph::addNode received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC); - // Graphs are node *sets*, so duplicates are forbidden. We allow nodes that are exactly equal, but disallow equal references. - foreach($this->_nodes as $key => $node) { - /* - ZE1 equality operators choke on the recursive cycle introduced by the _graph field in the Node object. - So, we'll check references the hard way (change $this->_nodes[$key] and check if the change reflects in - $node) - */ - $savedData = $this->_nodes[$key]; - $referenceIsEqualFlag = false; - $this->_nodes[$key] = true; - if ($node === true) { - $this->_nodes[$key] = false; - if ($node === false) $referenceIsEqualFlag = true; - } - $this->_nodes[$key] = $savedData; - if ($referenceIsEqualFlag) return Pear::raiseError('Structures_Graph::addNode received an object that is a duplicate for this dataset', STRUCTURES_GRAPH_ERROR_GENERIC); - } - $this->_nodes[] =& $newNode; - $newNode->setGraph($this); - } - /* }}} */ - - /* removeNode (unimplemented) {{{ */ - /** - * - * Remove a Node from the Graph - * - * @todo This is unimplemented - * @param Structures_Graph_Node The node to be removed from the graph - * @access public - */ - function removeNode(&$node) { - } - /* }}} */ - - /* getNodes {{{ */ - /** - * - * Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted. - * - * @access public - * @see Structures_Graph_Manipulator_TopologicalSorter - * @return array The set of nodes in this graph - */ - function &getNodes() { - return $this->_nodes; - } - /* }}} */ -} -?> - | -// +-----------------------------------------------------------------------------+ -// -/** - * This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator. - * - * @see Structures_Graph_Manipulator_AcyclicTest - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -/** */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph.php'; -/** */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php'; -/* }}} */ - -/* class Structures_Graph_Manipulator_AcyclicTest {{{ */ -/** - * The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator - * which tests whether a graph contains a cycle. - * - * The definition of an acyclic graph used in this manipulator is that of a - * DAG. The graph must be directed, or else it is considered cyclic, even when - * there are no arcs. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @package Structures_Graph - */ -class Structures_Graph_Manipulator_AcyclicTest { - /* _nonVisitedInDegree {{{ */ - /** - * - * This is a variant of Structures_Graph::inDegree which does - * not count nodes marked as visited. - * - * @access private - * @return integer Number of non-visited nodes that link to this one - */ - function _nonVisitedInDegree(&$node) { - $result = 0; - $graphNodes =& $node->_graph->getNodes(); - foreach (array_keys($graphNodes) as $key) { - if ((!$graphNodes[$key]->getMetadata('acyclic-test-visited')) && $graphNodes[$key]->connectsTo($node)) $result++; - } - return $result; - - } - /* }}} */ - - /* _isAcyclic {{{ */ - /** - * @access private - */ - function _isAcyclic(&$graph) { - // Mark every node as not visited - $nodes =& $graph->getNodes(); - $nodeKeys = array_keys($nodes); - $refGenerator = array(); - foreach($nodeKeys as $key) { - $refGenerator[] = false; - $nodes[$key]->setMetadata('acyclic-test-visited', $refGenerator[sizeof($refGenerator) - 1]); - } - - // Iteratively peel off leaf nodes - do { - // Find out which nodes are leafs (excluding visited nodes) - $leafNodes = array(); - foreach($nodeKeys as $key) { - if ((!$nodes[$key]->getMetadata('acyclic-test-visited')) && Structures_Graph_Manipulator_AcyclicTest::_nonVisitedInDegree($nodes[$key]) == 0) { - $leafNodes[] =& $nodes[$key]; - } - } - // Mark leafs as visited - for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) { - $visited =& $leafNodes[$i]->getMetadata('acyclic-test-visited'); - $visited = true; - $leafNodes[$i]->setMetadata('acyclic-test-visited', $visited); - } - } while (sizeof($leafNodes) > 0); - - // If graph is a DAG, there should be no non-visited nodes. Let's try to prove otherwise - $result = true; - foreach($nodeKeys as $key) if (!$nodes[$key]->getMetadata('acyclic-test-visited')) $result = false; - - // Cleanup visited marks - foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('acyclic-test-visited'); - - return $result; - } - /* }}} */ - - /* isAcyclic {{{ */ - /** - * - * isAcyclic returns true if a graph contains no cycles, false otherwise. - * - * @return boolean true iff graph is acyclic - * @access public - */ - function isAcyclic(&$graph) { - // We only test graphs - if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_AcyclicTest::isAcyclic received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC); - if (!$graph->isDirected()) return false; // Only directed graphs may be acyclic - - return Structures_Graph_Manipulator_AcyclicTest::_isAcyclic($graph); - } - /* }}} */ -} -/* }}} */ -?> - | -// +-----------------------------------------------------------------------------+ -// -/** - * This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class. - * - * @see Structures_Graph_Manipulator_TopologicalSorter - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -/** */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph.php'; -/** */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php'; -/** */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph/Manipulator/AcyclicTest.php'; -/* }}} */ - -/* class Structures_Graph_Manipulator_TopologicalSorter {{{ */ -/** - * The Structures_Graph_Manipulator_TopologicalSorter is a manipulator - * which is able to return the set of nodes in a graph, sorted by topological - * order. - * - * A graph may only be sorted topologically iff it's a DAG. You can test it - * with the Structures_Graph_Manipulator_AcyclicTest. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @see Structures_Graph_Manipulator_AcyclicTest - * @package Structures_Graph - */ -class Structures_Graph_Manipulator_TopologicalSorter { - /* _nonVisitedInDegree {{{ */ - /** - * - * This is a variant of Structures_Graph::inDegree which does - * not count nodes marked as visited. - * - * @access private - * @return integer Number of non-visited nodes that link to this one - */ - function _nonVisitedInDegree(&$node) { - $result = 0; - $graphNodes =& $node->_graph->getNodes(); - foreach (array_keys($graphNodes) as $key) { - if ((!$graphNodes[$key]->getMetadata('topological-sort-visited')) && $graphNodes[$key]->connectsTo($node)) $result++; - } - return $result; - - } - /* }}} */ - - /* _sort {{{ */ - /** - * @access private - */ - function _sort(&$graph) { - // Mark every node as not visited - $nodes =& $graph->getNodes(); - $nodeKeys = array_keys($nodes); - $refGenerator = array(); - foreach($nodeKeys as $key) { - $refGenerator[] = false; - $nodes[$key]->setMetadata('topological-sort-visited', $refGenerator[sizeof($refGenerator) - 1]); - } - - // Iteratively peel off leaf nodes - $topologicalLevel = 0; - do { - // Find out which nodes are leafs (excluding visited nodes) - $leafNodes = array(); - foreach($nodeKeys as $key) { - if ((!$nodes[$key]->getMetadata('topological-sort-visited')) && Structures_Graph_Manipulator_TopologicalSorter::_nonVisitedInDegree($nodes[$key]) == 0) { - $leafNodes[] =& $nodes[$key]; - } - } - // Mark leafs as visited - $refGenerator[] = $topologicalLevel; - for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) { - $visited =& $leafNodes[$i]->getMetadata('topological-sort-visited'); - $visited = true; - $leafNodes[$i]->setMetadata('topological-sort-visited', $visited); - $leafNodes[$i]->setMetadata('topological-sort-level', $refGenerator[sizeof($refGenerator) - 1]); - } - $topologicalLevel++; - } while (sizeof($leafNodes) > 0); - - // Cleanup visited marks - foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('topological-sort-visited'); - } - /* }}} */ - - /* sort {{{ */ - /** - * - * sort returns the graph's nodes, sorted by topological order. - * - * The result is an array with - * as many entries as topological levels. Each entry in this array is an array of nodes within - * the given topological level. - * - * @return array The graph's nodes, sorted by topological order. - * @access public - */ - function sort(&$graph) { - // We only sort graphs - if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC); - if (!Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph)) return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an graph that has cycles', STRUCTURES_GRAPH_ERROR_GENERIC); - - Structures_Graph_Manipulator_TopologicalSorter::_sort($graph); - $result = array(); - - // Fill out result array - $nodes =& $graph->getNodes(); - $nodeKeys = array_keys($nodes); - foreach($nodeKeys as $key) { - if (!array_key_exists($nodes[$key]->getMetadata('topological-sort-level'), $result)) $result[$nodes[$key]->getMetadata('topological-sort-level')] = array(); - $result[$nodes[$key]->getMetadata('topological-sort-level')][] =& $nodes[$key]; - $nodes[$key]->unsetMetadata('topological-sort-level'); - } - - return $result; - } - /* }}} */ -} -/* }}} */ -?> - | -// +-----------------------------------------------------------------------------+ -// -/** - * This file contains the definition of the Structures_Graph_Node class - * - * @see Structures_Graph_Node - * @package Structures_Graph - */ - -/* dependencies {{{ */ -/** */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -/** */ -require_once 'phar://go-pear.phar/' . 'Structures/Graph.php'; -/* }}} */ - -/* class Structures_Graph_Node {{{ */ -/** - * The Structures_Graph_Node class represents a Node that can be member of a - * graph node set. - * - * A graph node can contain data. Under this API, the node contains default data, - * and key index data. It behaves, thus, both as a regular data node, and as a - * dictionary (or associative array) node. - * - * Regular data is accessed via getData and setData. Key indexed data is accessed - * via getMetadata and setMetadata. - * - * @author Sérgio Carvalho - * @copyright (c) 2004 by Sérgio Carvalho - * @package Structures_Graph - */ -/* }}} */ -class Structures_Graph_Node { - /* fields {{{ */ - /** - * @access private - */ - var $_data = null; - /** @access private */ - var $_metadata = array(); - /** @access private */ - var $_arcs = array(); - /** @access private */ - var $_graph = null; - /* }}} */ - - /* Constructor {{{ */ - /** - * - * Constructor - * - * @access public - */ - function Structures_Graph_Node() { - } - /* }}} */ - - /* getGraph {{{ */ - /** - * - * Node graph getter - * - * @return Structures_Graph Graph where node is stored - * @access public - */ - function &getGraph() { - return $this->_graph; - } - /* }}} */ - - /* setGraph {{{ */ - /** - * - * Node graph setter. This method should not be called directly. Use Graph::addNode instead. - * - * @param Structures_Graph Set the graph for this node. - * @see Structures_Graph::addNode() - * @access public - */ - function setGraph(&$graph) { - $this->_graph =& $graph; - } - /* }}} */ - - /* getData {{{ */ - /** - * - * Node data getter. - * - * Each graph node can contain a reference to one variable. This is the getter for that reference. - * - * @return mixed Data stored in node - * @access public - */ - function &getData() { - return $this->_data; - } - /* }}} */ - - /* setData {{{ */ - /** - * - * Node data setter - * - * Each graph node can contain a reference to one variable. This is the setter for that reference. - * - * @return mixed Data to store in node - * @access public - */ - function setData($data) { - $this->_data =& $data; - } - /* }}} */ - - /* metadataKeyExists {{{ */ - /** - * - * Test for existence of metadata under a given key. - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method tests whether a given metadata key exists for this node. - * - * @param string Key to test - * @return boolean - * @access public - */ - function metadataKeyExists($key) { - return array_key_exists($key, $this->_metadata); - } - /* }}} */ - - /* getMetadata {{{ */ - /** - * - * Node metadata getter - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method gets the data under the given key. If the key does - * not exist, an error will be thrown, so testing using metadataKeyExists might be needed. - * - * @param string Key - * @param boolean nullIfNonexistent (defaults to false). - * @return mixed Metadata Data stored in node under given key - * @see metadataKeyExists - * @access public - */ - function &getMetadata($key, $nullIfNonexistent = false) { - if (array_key_exists($key, $this->_metadata)) { - return $this->_metadata[$key]; - } else { - if ($nullIfNonexistent) { - $a = null; - return $a; - } else { - $a = Pear::raiseError('Structures_Graph_Node::getMetadata: Requested key does not exist', STRUCTURES_GRAPH_ERROR_GENERIC); - return $a; - } - } - } - /* }}} */ - - /* unsetMetadata {{{ */ - /** - * - * Delete metadata by key - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method removes any data that might be stored under the provided key. - * If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence. - * - * @param string Key - * @access public - */ - function unsetMetadata($key) { - if (array_key_exists($key, $this->_metadata)) unset($this->_metadata[$key]); - } - /* }}} */ - - /* setMetadata {{{ */ - /** - * - * Node metadata setter - * - * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an - * associative array or in a dictionary. This method stores data under the given key. If the key already exists, - * previously stored data is discarded. - * - * @param string Key - * @param mixed Data - * @access public - */ - function setMetadata($key, $data) { - $this->_metadata[$key] =& $data; - } - /* }}} */ - - /* _connectTo {{{ */ - /** @access private */ - function _connectTo(&$destinationNode) { - $this->_arcs[] =& $destinationNode; - } - /* }}} */ - - /* connectTo {{{ */ - /** - * - * Connect this node to another one. - * - * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created. - * - * @param Structures_Graph_Node Node to connect to - * @access public - */ - function connectTo(&$destinationNode) { - // We only connect to nodes - if (!is_a($destinationNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph_Node::connectTo received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC); - // Nodes must already be in graphs to be connected - if ($this->_graph == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC); - if ($destinationNode->getGraph() == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect to a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC); - // Connect here - $this->_connectTo($destinationNode); - // If graph is undirected, connect back - if (!$this->_graph->isDirected()) { - $destinationNode->_connectTo($this); - } - } - /* }}} */ - - /* getNeighbours {{{ */ - /** - * - * Return nodes connected to this one. - * - * @return array Array of nodes - * @access public - */ - function getNeighbours() { - return $this->_arcs; - } - /* }}} */ - - /* connectsTo {{{ */ - /** - * - * Test wether this node has an arc to the target node - * - * @return boolean True if the two nodes are connected - * @access public - */ - function connectsTo(&$target) { - $copy = $target; - $arcKeys = array_keys($this->_arcs); - foreach($arcKeys as $key) { - /* ZE1 chokes on this expression: - if ($target === $arc) return true; - so, we'll use more convoluted stuff - */ - $arc =& $this->_arcs[$key]; - $target = true; - if ($arc === true) { - $target = false; - if ($arc === false) { - $target = $copy; - return true; - } - } - } - $target = $copy; - return false; - } - /* }}} */ - - /* inDegree {{{ */ - /** - * - * Calculate the in degree of the node. - * - * The indegree for a node is the number of arcs entering the node. For non directed graphs, - * the indegree is equal to the outdegree. - * - * @return integer In degree of the node - * @access public - */ - function inDegree() { - if ($this->_graph == null) return 0; - if (!$this->_graph->isDirected()) return $this->outDegree(); - $result = 0; - $graphNodes =& $this->_graph->getNodes(); - foreach (array_keys($graphNodes) as $key) { - if ($graphNodes[$key]->connectsTo($this)) $result++; - } - return $result; - - } - /* }}} */ - - /* outDegree {{{ */ - /** - * - * Calculate the out degree of the node. - * - * The outdegree for a node is the number of arcs exiting the node. For non directed graphs, - * the outdegree is always equal to the indegree. - * - * @return integer Out degree of the node - * @access public - */ - function outDegree() { - if ($this->_graph == null) return 0; - return sizeof($this->_arcs); - } - /* }}} */ -} -?> - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: System.php 276386 2009-02-24 23:52:56Z dufuz $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'phar://go-pear.phar/' . 'PEAR.php'; -require_once 'phar://go-pear.phar/' . 'Console/Getopt.php'; - -$GLOBALS['_System_temp_files'] = array(); - -/** -* System offers cross plattform compatible system functions -* -* Static functions for different operations. Should work under -* Unix and Windows. The names and usage has been taken from its respectively -* GNU commands. The functions will return (bool) false on error and will -* trigger the error with the PHP trigger_error() function (you can silence -* the error by prefixing a '@' sign after the function call, but this -* is not recommended practice. Instead use an error handler with -* {@link set_error_handler()}). -* -* Documentation on this class you can find in: -* http://pear.php.net/manual/ -* -* Example usage: -* if (!@System::rm('-r file1 dir1')) { -* print "could not delete file1 or dir1"; -* } -* -* In case you need to to pass file names with spaces, -* pass the params as an array: -* -* System::rm(array('-r', $file1, $dir1)); -* -* @category pear -* @package System -* @author Tomas V.V. Cox -* @copyright 1997-2006 The PHP Group -* @license http://opensource.org/licenses/bsd-license.php New BSD License -* @version Release: 1.9.0 -* @link http://pear.php.net/package/PEAR -* @since Class available since Release 0.1 -* @static -*/ -class System -{ - /** - * returns the commandline arguments of a function - * - * @param string $argv the commandline - * @param string $short_options the allowed option short-tags - * @param string $long_options the allowed option long-tags - * @return array the given options and there values - * @static - * @access private - */ - function _parseArgs($argv, $short_options, $long_options = null) - { - if (!is_array($argv) && $argv !== null) { - $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY); - } - return Console_Getopt::getopt2($argv, $short_options); - } - - /** - * Output errors with PHP trigger_error(). You can silence the errors - * with prefixing a "@" sign to the function call: @System::mkdir(..); - * - * @param mixed $error a PEAR error or a string with the error message - * @return bool false - * @static - * @access private - */ - function raiseError($error) - { - if (PEAR::isError($error)) { - $error = $error->getMessage(); - } - trigger_error($error, E_USER_WARNING); - return false; - } - - /** - * Creates a nested array representing the structure of a directory - * - * System::_dirToStruct('dir1', 0) => - * Array - * ( - * [dirs] => Array - * ( - * [0] => dir1 - * ) - * - * [files] => Array - * ( - * [0] => dir1/file2 - * [1] => dir1/file3 - * ) - * ) - * @param string $sPath Name of the directory - * @param integer $maxinst max. deep of the lookup - * @param integer $aktinst starting deep of the lookup - * @param bool $silent if true, do not emit errors. - * @return array the structure of the dir - * @static - * @access private - */ - function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) - { - $struct = array('dirs' => array(), 'files' => array()); - if (($dir = @opendir($sPath)) === false) { - if (!$silent) { - System::raiseError("Could not open dir $sPath"); - } - return $struct; // XXX could not open error - } - - $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? - $list = array(); - while (false !== ($file = readdir($dir))) { - if ($file != '.' && $file != '..') { - $list[] = $file; - } - } - - closedir($dir); - natsort($list); - if ($aktinst < $maxinst || $maxinst == 0) { - foreach ($list as $val) { - $path = $sPath . DIRECTORY_SEPARATOR . $val; - if (is_dir($path) && !is_link($path)) { - $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); - $struct = array_merge_recursive($struct, $tmp); - } else { - $struct['files'][] = $path; - } - } - } - - return $struct; - } - - /** - * Creates a nested array representing the structure of a directory and files - * - * @param array $files Array listing files and dirs - * @return array - * @static - * @see System::_dirToStruct() - */ - function _multipleToStruct($files) - { - $struct = array('dirs' => array(), 'files' => array()); - settype($files, 'array'); - foreach ($files as $file) { - if (is_dir($file) && !is_link($file)) { - $tmp = System::_dirToStruct($file, 0); - $struct = array_merge_recursive($tmp, $struct); - } else { - if (!in_array($file, $struct['files'])) { - $struct['files'][] = $file; - } - } - } - return $struct; - } - - /** - * The rm command for removing files. - * Supports multiple files and dirs and also recursive deletes - * - * @param string $args the arguments for rm - * @return mixed PEAR_Error or true for success - * @static - * @access public - */ - function rm($args) - { - $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - foreach ($opts[0] as $opt) { - if ($opt[0] == 'r') { - $do_recursive = true; - } - } - $ret = true; - if (isset($do_recursive)) { - $struct = System::_multipleToStruct($opts[1]); - foreach ($struct['files'] as $file) { - if (!@unlink($file)) { - $ret = false; - } - } - - rsort($struct['dirs']); - foreach ($struct['dirs'] as $dir) { - if (!@rmdir($dir)) { - $ret = false; - } - } - } else { - foreach ($opts[1] as $file) { - $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; - if (!@$delete($file)) { - $ret = false; - } - } - } - return $ret; - } - - /** - * Make directories. - * - * The -p option will create parent directories - * @param string $args the name of the director(y|ies) to create - * @return bool True for success - * @static - * @access public - */ - function mkDir($args) - { - $opts = System::_parseArgs($args, 'pm:'); - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - - $mode = 0777; // default mode - foreach ($opts[0] as $opt) { - if ($opt[0] == 'p') { - $create_parents = true; - } elseif ($opt[0] == 'm') { - // if the mode is clearly an octal number (starts with 0) - // convert it to decimal - if (strlen($opt[1]) && $opt[1]{0} == '0') { - $opt[1] = octdec($opt[1]); - } else { - // convert to int - $opt[1] += 0; - } - $mode = $opt[1]; - } - } - - $ret = true; - if (isset($create_parents)) { - foreach ($opts[1] as $dir) { - $dirstack = array(); - while ((!file_exists($dir) || !is_dir($dir)) && - $dir != DIRECTORY_SEPARATOR) { - array_unshift($dirstack, $dir); - $dir = dirname($dir); - } - - while ($newdir = array_shift($dirstack)) { - if (!is_writeable(dirname($newdir))) { - $ret = false; - break; - } - - if (!mkdir($newdir, $mode)) { - $ret = false; - } - } - } - } else { - foreach($opts[1] as $dir) { - if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { - $ret = false; - } - } - } - - return $ret; - } - - /** - * Concatenate files - * - * Usage: - * 1) $var = System::cat('sample.txt test.txt'); - * 2) System::cat('sample.txt test.txt > final.txt'); - * 3) System::cat('sample.txt test.txt >> final.txt'); - * - * Note: as the class use fopen, urls should work also (test that) - * - * @param string $args the arguments - * @return boolean true on success - * @static - * @access public - */ - function &cat($args) - { - $ret = null; - $files = array(); - if (!is_array($args)) { - $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); - } - - $count_args = count($args); - for ($i = 0; $i < $count_args; $i++) { - if ($args[$i] == '>') { - $mode = 'wb'; - $outputfile = $args[$i+1]; - break; - } elseif ($args[$i] == '>>') { - $mode = 'ab+'; - $outputfile = $args[$i+1]; - break; - } else { - $files[] = $args[$i]; - } - } - $outputfd = false; - if (isset($mode)) { - if (!$outputfd = fopen($outputfile, $mode)) { - $err = System::raiseError("Could not open $outputfile"); - return $err; - } - $ret = true; - } - foreach ($files as $file) { - if (!$fd = fopen($file, 'r')) { - System::raiseError("Could not open $file"); - continue; - } - while ($cont = fread($fd, 2048)) { - if (is_resource($outputfd)) { - fwrite($outputfd, $cont); - } else { - $ret .= $cont; - } - } - fclose($fd); - } - if (is_resource($outputfd)) { - fclose($outputfd); - } - return $ret; - } - - /** - * Creates temporary files or directories. This function will remove - * the created files when the scripts finish its execution. - * - * Usage: - * 1) $tempfile = System::mktemp("prefix"); - * 2) $tempdir = System::mktemp("-d prefix"); - * 3) $tempfile = System::mktemp(); - * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); - * - * prefix -> The string that will be prepended to the temp name - * (defaults to "tmp"). - * -d -> A temporary dir will be created instead of a file. - * -t -> The target dir where the temporary (file|dir) will be created. If - * this param is missing by default the env vars TMP on Windows or - * TMPDIR in Unix will be used. If these vars are also missing - * c:\windows\temp or /tmp will be used. - * - * @param string $args The arguments - * @return mixed the full path of the created (file|dir) or false - * @see System::tmpdir() - * @static - * @access public - */ - function mktemp($args = null) - { - static $first_time = true; - $opts = System::_parseArgs($args, 't:d'); - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - - foreach ($opts[0] as $opt) { - if ($opt[0] == 'd') { - $tmp_is_dir = true; - } elseif ($opt[0] == 't') { - $tmpdir = $opt[1]; - } - } - - $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; - if (!isset($tmpdir)) { - $tmpdir = System::tmpdir(); - } - - if (!System::mkDir(array('-p', $tmpdir))) { - return false; - } - - $tmp = tempnam($tmpdir, $prefix); - if (isset($tmp_is_dir)) { - unlink($tmp); // be careful possible race condition here - if (!mkdir($tmp, 0700)) { - return System::raiseError("Unable to create temporary directory $tmpdir"); - } - } - - $GLOBALS['_System_temp_files'][] = $tmp; - if (isset($tmp_is_dir)) { - //$GLOBALS['_System_temp_files'][] = dirname($tmp); - } - - if ($first_time) { - PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); - $first_time = false; - } - - return $tmp; - } - - /** - * Remove temporary files created my mkTemp. This function is executed - * at script shutdown time - * - * @static - * @access private - */ - function _removeTmpFiles() - { - if (count($GLOBALS['_System_temp_files'])) { - $delete = $GLOBALS['_System_temp_files']; - array_unshift($delete, '-r'); - System::rm($delete); - $GLOBALS['_System_temp_files'] = array(); - } - } - - /** - * Get the path of the temporal directory set in the system - * by looking in its environments variables. - * Note: php.ini-recommended removes the "E" from the variables_order setting, - * making unavaible the $_ENV array, that s why we do tests with _ENV - * - * @static - * @return string The temporary directory on the system - */ - function tmpdir() - { - if (OS_WINDOWS) { - if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { - return $var; - } - if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { - return $var; - } - if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { - return $var; - } - if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { - return $var; - } - return getenv('SystemRoot') . '\temp'; - } - if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { - return $var; - } - return realpath('/tmp'); - } - - /** - * The "which" command (show the full path of a command) - * - * @param string $program The command to search for - * @param mixed $fallback Value to return if $program is not found - * - * @return mixed A string with the full path or false if not found - * @static - * @author Stig Bakken - */ - function which($program, $fallback = false) - { - // enforce API - if (!is_string($program) || '' == $program) { - return $fallback; - } - - // full path given - if (basename($program) != $program) { - $path_elements[] = dirname($program); - $program = basename($program); - } else { - // Honor safe mode - if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) { - $path = getenv('PATH'); - if (!$path) { - $path = getenv('Path'); // some OSes are just stupid enough to do this - } - } - $path_elements = explode(PATH_SEPARATOR, $path); - } - - if (OS_WINDOWS) { - $exe_suffixes = getenv('PATHEXT') - ? explode(PATH_SEPARATOR, getenv('PATHEXT')) - : array('.exe','.bat','.cmd','.com'); - // allow passing a command.exe param - if (strpos($program, '.') !== false) { - array_unshift($exe_suffixes, ''); - } - // is_executable() is not available on windows for PHP4 - $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file'; - } else { - $exe_suffixes = array(''); - $pear_is_executable = 'is_executable'; - } - - foreach ($exe_suffixes as $suff) { - foreach ($path_elements as $dir) { - $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; - if (@$pear_is_executable($file)) { - return $file; - } - } - } - return $fallback; - } - - /** - * The "find" command - * - * Usage: - * - * System::find($dir); - * System::find("$dir -type d"); - * System::find("$dir -type f"); - * System::find("$dir -name *.php"); - * System::find("$dir -name *.php -name *.htm*"); - * System::find("$dir -maxdepth 1"); - * - * Params implmented: - * $dir -> Start the search at this directory - * -type d -> return only directories - * -type f -> return only files - * -maxdepth -> max depth of recursion - * -name -> search pattern (bash style). Multiple -name param allowed - * - * @param mixed Either array or string with the command line - * @return array Array of found files - * @static - * - */ - function find($args) - { - if (!is_array($args)) { - $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); - } - $dir = realpath(array_shift($args)); - if (!$dir) { - return array(); - } - $patterns = array(); - $depth = 0; - $do_files = $do_dirs = true; - $args_count = count($args); - for ($i = 0; $i < $args_count; $i++) { - switch ($args[$i]) { - case '-type': - if (in_array($args[$i+1], array('d', 'f'))) { - if ($args[$i+1] == 'd') { - $do_files = false; - } else { - $do_dirs = false; - } - } - $i++; - break; - case '-name': - $name = preg_quote($args[$i+1], '#'); - // our magic characters ? and * have just been escaped, - // so now we change the escaped versions to PCRE operators - $name = strtr($name, array('\?' => '.', '\*' => '.*')); - $patterns[] = '('.$name.')'; - $i++; - break; - case '-maxdepth': - $depth = $args[$i+1]; - break; - } - } - $path = System::_dirToStruct($dir, $depth, 0, true); - if ($do_files && $do_dirs) { - $files = array_merge($path['files'], $path['dirs']); - } elseif ($do_dirs) { - $files = $path['dirs']; - } else { - $files = $path['files']; - } - if (count($patterns)) { - $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); - $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; - $ret = array(); - $files_count = count($files); - for ($i = 0; $i < $files_count; $i++) { - // only search in the part of the file below the current directory - $filepart = basename($files[$i]); - if (preg_match($pattern, $filepart)) { - $ret[] = $files[$i]; - } - } - return $ret; - } - return $files; - } -} - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @category XML - * @package XML_Util - * @author Stephan Schmidt - * @copyright 2003-2008 Stephan Schmidt - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: Util.php 275418 2009-02-09 14:23:42Z ashnazg $ - * @link http://pear.php.net/package/XML_Util - */ - -/** - * error code for invalid chars in XML name - */ -define('XML_UTIL_ERROR_INVALID_CHARS', 51); - -/** - * error code for invalid chars in XML name - */ -define('XML_UTIL_ERROR_INVALID_START', 52); - -/** - * error code for non-scalar tag content - */ -define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60); - -/** - * error code for missing tag name - */ -define('XML_UTIL_ERROR_NO_TAG_NAME', 61); - -/** - * replace XML entities - */ -define('XML_UTIL_REPLACE_ENTITIES', 1); - -/** - * embedd content in a CData Section - */ -define('XML_UTIL_CDATA_SECTION', 5); - -/** - * do not replace entitites - */ -define('XML_UTIL_ENTITIES_NONE', 0); - -/** - * replace all XML entitites - * This setting will replace <, >, ", ' and & - */ -define('XML_UTIL_ENTITIES_XML', 1); - -/** - * replace only required XML entitites - * This setting will replace <, " and & - */ -define('XML_UTIL_ENTITIES_XML_REQUIRED', 2); - -/** - * replace HTML entitites - * @link http://www.php.net/htmlentities - */ -define('XML_UTIL_ENTITIES_HTML', 3); - -/** - * Collapse all empty tags. - */ -define('XML_UTIL_COLLAPSE_ALL', 1); - -/** - * Collapse only empty XHTML tags that have no end tag. - */ -define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2); - -/** - * utility class for working with XML documents - * - - * @category XML - * @package XML_Util - * @author Stephan Schmidt - * @copyright 2003-2008 Stephan Schmidt - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version Release: @version@ - * @link http://pear.php.net/package/XML_Util - */ -class XML_Util -{ - /** - * return API version - * - * @return string $version API version - * @access public - * @static - */ - function apiVersion() - { - return '1.1'; - } - - /** - * replace XML entities - * - * With the optional second parameter, you may select, which - * entities should be replaced. - * - * - * require_once 'XML/Util.php'; - * - * // replace XML entites: - * $string = XML_Util::replaceEntities('This string contains < & >.'); - * - * - * With the optional third parameter, you may pass the character encoding - * - * require_once 'XML/Util.php'; - * - * // replace XML entites in UTF-8: - * $string = XML_Util::replaceEntities( - * 'This string contains < & > as well as ä, ö, ß, à and ê', - * XML_UTIL_ENTITIES_HTML, - * 'UTF-8' - * ); - * - * - * @param string $string string where XML special chars - * should be replaced - * @param int $replaceEntities setting for entities in attribute values - * (one of XML_UTIL_ENTITIES_XML, - * XML_UTIL_ENTITIES_XML_REQUIRED, - * XML_UTIL_ENTITIES_HTML) - * @param string $encoding encoding value (if any)... - * must be a valid encoding as determined - * by the htmlentities() function - * - * @return string string with replaced chars - * @access public - * @static - * @see reverseEntities() - */ - function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML, - $encoding = 'ISO-8859-1') - { - switch ($replaceEntities) { - case XML_UTIL_ENTITIES_XML: - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - '\'' => ''' )); - break; - case XML_UTIL_ENTITIES_XML_REQUIRED: - return strtr($string, array( - '&' => '&', - '<' => '<', - '"' => '"' )); - break; - case XML_UTIL_ENTITIES_HTML: - return htmlentities($string, ENT_COMPAT, $encoding); - break; - } - return $string; - } - - /** - * reverse XML entities - * - * With the optional second parameter, you may select, which - * entities should be reversed. - * - * - * require_once 'XML/Util.php'; - * - * // reverse XML entites: - * $string = XML_Util::reverseEntities('This string contains < & >.'); - * - * - * With the optional third parameter, you may pass the character encoding - * - * require_once 'XML/Util.php'; - * - * // reverse XML entites in UTF-8: - * $string = XML_Util::reverseEntities( - * 'This string contains < & > as well as' - * . ' ä, ö, ß, à and ê', - * XML_UTIL_ENTITIES_HTML, - * 'UTF-8' - * ); - * - * - * @param string $string string where XML special chars - * should be replaced - * @param int $replaceEntities setting for entities in attribute values - * (one of XML_UTIL_ENTITIES_XML, - * XML_UTIL_ENTITIES_XML_REQUIRED, - * XML_UTIL_ENTITIES_HTML) - * @param string $encoding encoding value (if any)... - * must be a valid encoding as determined - * by the html_entity_decode() function - * - * @return string string with replaced chars - * @access public - * @static - * @see replaceEntities() - */ - function reverseEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML, - $encoding = 'ISO-8859-1') - { - switch ($replaceEntities) { - case XML_UTIL_ENTITIES_XML: - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - ''' => '\'' )); - break; - case XML_UTIL_ENTITIES_XML_REQUIRED: - return strtr($string, array( - '&' => '&', - '<' => '<', - '"' => '"' )); - break; - case XML_UTIL_ENTITIES_HTML: - return html_entity_decode($string, ENT_COMPAT, $encoding); - break; - } - return $string; - } - - /** - * build an xml declaration - * - * - * require_once 'XML/Util.php'; - * - * // get an XML declaration: - * $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true); - * - * - * @param string $version xml version - * @param string $encoding character encoding - * @param bool $standalone document is standalone (or not) - * - * @return string xml declaration - * @access public - * @static - * @uses attributesToString() to serialize the attributes of the XML declaration - */ - function getXMLDeclaration($version = '1.0', $encoding = null, - $standalone = null) - { - $attributes = array( - 'version' => $version, - ); - // add encoding - if ($encoding !== null) { - $attributes['encoding'] = $encoding; - } - // add standalone, if specified - if ($standalone !== null) { - $attributes['standalone'] = $standalone ? 'yes' : 'no'; - } - - return sprintf('', - XML_Util::attributesToString($attributes, false)); - } - - /** - * build a document type declaration - * - * - * require_once 'XML/Util.php'; - * - * // get a doctype declaration: - * $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd'); - * - * - * @param string $root name of the root tag - * @param string $uri uri of the doctype definition - * (or array with uri and public id) - * @param string $internalDtd internal dtd entries - * - * @return string doctype declaration - * @access public - * @static - * @since 0.2 - */ - function getDocTypeDeclaration($root, $uri = null, $internalDtd = null) - { - if (is_array($uri)) { - $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']); - } elseif (!empty($uri)) { - $ref = sprintf(' SYSTEM "%s"', $uri); - } else { - $ref = ''; - } - - if (empty($internalDtd)) { - return sprintf('', $root, $ref); - } else { - return sprintf("", $root, $ref, $internalDtd); - } - } - - /** - * create string representation of an attribute list - * - * - * require_once 'XML/Util.php'; - * - * // build an attribute string - * $att = array( - * 'foo' => 'bar', - * 'argh' => 'tomato' - * ); - * - * $attList = XML_Util::attributesToString($att); - * - * - * @param array $attributes attribute array - * @param bool|array $sort sort attribute list alphabetically, - * may also be an assoc array containing - * the keys 'sort', 'multiline', 'indent', - * 'linebreak' and 'entities' - * @param bool $multiline use linebreaks, if more than - * one attribute is given - * @param string $indent string used for indentation of - * multiline attributes - * @param string $linebreak string used for linebreaks of - * multiline attributes - * @param int $entities setting for entities in attribute values - * (one of XML_UTIL_ENTITIES_NONE, - * XML_UTIL_ENTITIES_XML, - * XML_UTIL_ENTITIES_XML_REQUIRED, - * XML_UTIL_ENTITIES_HTML) - * - * @return string string representation of the attributes - * @access public - * @static - * @uses replaceEntities() to replace XML entities in attribute values - * @todo allow sort also to be an options array - */ - function attributesToString($attributes, $sort = true, $multiline = false, - $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML) - { - /* - * second parameter may be an array - */ - if (is_array($sort)) { - if (isset($sort['multiline'])) { - $multiline = $sort['multiline']; - } - if (isset($sort['indent'])) { - $indent = $sort['indent']; - } - if (isset($sort['linebreak'])) { - $multiline = $sort['linebreak']; - } - if (isset($sort['entities'])) { - $entities = $sort['entities']; - } - if (isset($sort['sort'])) { - $sort = $sort['sort']; - } else { - $sort = true; - } - } - $string = ''; - if (is_array($attributes) && !empty($attributes)) { - if ($sort) { - ksort($attributes); - } - if ( !$multiline || count($attributes) == 1) { - foreach ($attributes as $key => $value) { - if ($entities != XML_UTIL_ENTITIES_NONE) { - if ($entities === XML_UTIL_CDATA_SECTION) { - $entities = XML_UTIL_ENTITIES_XML; - } - $value = XML_Util::replaceEntities($value, $entities); - } - $string .= ' ' . $key . '="' . $value . '"'; - } - } else { - $first = true; - foreach ($attributes as $key => $value) { - if ($entities != XML_UTIL_ENTITIES_NONE) { - $value = XML_Util::replaceEntities($value, $entities); - } - if ($first) { - $string .= ' ' . $key . '="' . $value . '"'; - $first = false; - } else { - $string .= $linebreak . $indent . $key . '="' . $value . '"'; - } - } - } - } - return $string; - } - - /** - * Collapses empty tags. - * - * @param string $xml XML - * @param int $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL) - * or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones. - * - * @return string XML - * @access public - * @static - * @todo PEAR CS - unable to avoid "space after open parens" error - * in the IF branch - */ - function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL) - { - if ($mode == XML_UTIL_COLLAPSE_XHTML_ONLY) { - return preg_replace( - '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|' - . 'param)([^>]*)><\/\\1>/s', - '<\\1\\2 />', - $xml); - } else { - return preg_replace('/<(\w+)([^>]*)><\/\\1>/s', '<\\1\\2 />', $xml); - } - } - - /** - * create a tag - * - * This method will call XML_Util::createTagFromArray(), which - * is more flexible. - * - * - * require_once 'XML/Util.php'; - * - * // create an XML tag: - * $tag = XML_Util::createTag('myNs:myTag', - * array('foo' => 'bar'), - * 'This is inside the tag', - * 'http://www.w3c.org/myNs#'); - * - * - * @param string $qname qualified tagname (including namespace) - * @param array $attributes array containg attributes - * @param mixed $content the content - * @param string $namespaceUri URI of the namespace - * @param int $replaceEntities whether to replace XML special chars in - * content, embedd it in a CData section - * or none of both - * @param bool $multiline whether to create a multiline tag where - * each attribute gets written to a single line - * @param string $indent string used to indent attributes - * (_auto indents attributes so they start - * at the same column) - * @param string $linebreak string used for linebreaks - * @param bool $sortAttributes Whether to sort the attributes or not - * - * @return string XML tag - * @access public - * @static - * @see createTagFromArray() - * @uses createTagFromArray() to create the tag - */ - function createTag($qname, $attributes = array(), $content = null, - $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, - $multiline = false, $indent = '_auto', $linebreak = "\n", - $sortAttributes = true) - { - $tag = array( - 'qname' => $qname, - 'attributes' => $attributes - ); - - // add tag content - if ($content !== null) { - $tag['content'] = $content; - } - - // add namespace Uri - if ($namespaceUri !== null) { - $tag['namespaceUri'] = $namespaceUri; - } - - return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, - $indent, $linebreak, $sortAttributes); - } - - /** - * create a tag from an array - * this method awaits an array in the following format - *
    -     * array(
    -     *     // qualified name of the tag
    -     *     'qname' => $qname
    -     *
    -     *     // namespace prefix (optional, if qname is specified or no namespace)
    -     *     'namespace' => $namespace
    -     *
    -     *     // local part of the tagname (optional, if qname is specified)
    -     *     'localpart' => $localpart,
    -     *
    -     *     // array containing all attributes (optional)
    -     *     'attributes' => array(),
    -     *
    -     *     // tag content (optional)
    -     *     'content' => $content,
    -     *
    -     *     // namespaceUri for the given namespace (optional)
    -     *     'namespaceUri' => $namespaceUri
    -     * )
    -     * 
    - * - * - * require_once 'XML/Util.php'; - * - * $tag = array( - * 'qname' => 'foo:bar', - * 'namespaceUri' => 'http://foo.com', - * 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'), - * 'content' => 'I\'m inside the tag', - * ); - * // creating a tag with qualified name and namespaceUri - * $string = XML_Util::createTagFromArray($tag); - * - * - * @param array $tag tag definition - * @param int $replaceEntities whether to replace XML special chars in - * content, embedd it in a CData section - * or none of both - * @param bool $multiline whether to create a multiline tag where each - * attribute gets written to a single line - * @param string $indent string used to indent attributes - * (_auto indents attributes so they start - * at the same column) - * @param string $linebreak string used for linebreaks - * @param bool $sortAttributes Whether to sort the attributes or not - * - * @return string XML tag - * @access public - * @static - * @see createTag() - * @uses attributesToString() to serialize the attributes of the tag - * @uses splitQualifiedName() to get local part and namespace of a qualified name - * @uses createCDataSection() - * @uses raiseError() - */ - function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, - $multiline = false, $indent = '_auto', $linebreak = "\n", - $sortAttributes = true) - { - if (isset($tag['content']) && !is_scalar($tag['content'])) { - return XML_Util::raiseError('Supplied non-scalar value as tag content', - XML_UTIL_ERROR_NON_SCALAR_CONTENT); - } - - if (!isset($tag['qname']) && !isset($tag['localPart'])) { - return XML_Util::raiseError('You must either supply a qualified name ' - . '(qname) or local tag name (localPart).', - XML_UTIL_ERROR_NO_TAG_NAME); - } - - // if no attributes hav been set, use empty attributes - if (!isset($tag['attributes']) || !is_array($tag['attributes'])) { - $tag['attributes'] = array(); - } - - if (isset($tag['namespaces'])) { - foreach ($tag['namespaces'] as $ns => $uri) { - $tag['attributes']['xmlns:' . $ns] = $uri; - } - } - - if (!isset($tag['qname'])) { - // qualified name is not given - - // check for namespace - if (isset($tag['namespace']) && !empty($tag['namespace'])) { - $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart']; - } else { - $tag['qname'] = $tag['localPart']; - } - } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) { - // namespace URI is set, but no namespace - - $parts = XML_Util::splitQualifiedName($tag['qname']); - - $tag['localPart'] = $parts['localPart']; - if (isset($parts['namespace'])) { - $tag['namespace'] = $parts['namespace']; - } - } - - if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) { - // is a namespace given - if (isset($tag['namespace']) && !empty($tag['namespace'])) { - $tag['attributes']['xmlns:' . $tag['namespace']] = - $tag['namespaceUri']; - } else { - // define this Uri as the default namespace - $tag['attributes']['xmlns'] = $tag['namespaceUri']; - } - } - - // check for multiline attributes - if ($multiline === true) { - if ($indent === '_auto') { - $indent = str_repeat(' ', (strlen($tag['qname'])+2)); - } - } - - // create attribute list - $attList = XML_Util::attributesToString($tag['attributes'], - $sortAttributes, $multiline, $indent, $linebreak, $replaceEntities); - if (!isset($tag['content']) || (string)$tag['content'] == '') { - $tag = sprintf('<%s%s />', $tag['qname'], $attList); - } else { - switch ($replaceEntities) { - case XML_UTIL_ENTITIES_NONE: - break; - case XML_UTIL_CDATA_SECTION: - $tag['content'] = XML_Util::createCDataSection($tag['content']); - break; - default: - $tag['content'] = XML_Util::replaceEntities($tag['content'], - $replaceEntities); - break; - } - $tag = sprintf('<%s%s>%s', $tag['qname'], $attList, $tag['content'], - $tag['qname']); - } - return $tag; - } - - /** - * create a start element - * - * - * require_once 'XML/Util.php'; - * - * // create an XML start element: - * $tag = XML_Util::createStartElement('myNs:myTag', - * array('foo' => 'bar') ,'http://www.w3c.org/myNs#'); - * - * - * @param string $qname qualified tagname (including namespace) - * @param array $attributes array containg attributes - * @param string $namespaceUri URI of the namespace - * @param bool $multiline whether to create a multiline tag where each - * attribute gets written to a single line - * @param string $indent string used to indent attributes (_auto indents - * attributes so they start at the same column) - * @param string $linebreak string used for linebreaks - * @param bool $sortAttributes Whether to sort the attributes or not - * - * @return string XML start element - * @access public - * @static - * @see createEndElement(), createTag() - */ - function createStartElement($qname, $attributes = array(), $namespaceUri = null, - $multiline = false, $indent = '_auto', $linebreak = "\n", - $sortAttributes = true) - { - // if no attributes hav been set, use empty attributes - if (!isset($attributes) || !is_array($attributes)) { - $attributes = array(); - } - - if ($namespaceUri != null) { - $parts = XML_Util::splitQualifiedName($qname); - } - - // check for multiline attributes - if ($multiline === true) { - if ($indent === '_auto') { - $indent = str_repeat(' ', (strlen($qname)+2)); - } - } - - if ($namespaceUri != null) { - // is a namespace given - if (isset($parts['namespace']) && !empty($parts['namespace'])) { - $attributes['xmlns:' . $parts['namespace']] = $namespaceUri; - } else { - // define this Uri as the default namespace - $attributes['xmlns'] = $namespaceUri; - } - } - - // create attribute list - $attList = XML_Util::attributesToString($attributes, $sortAttributes, - $multiline, $indent, $linebreak); - $element = sprintf('<%s%s>', $qname, $attList); - return $element; - } - - /** - * create an end element - * - * - * require_once 'XML/Util.php'; - * - * // create an XML start element: - * $tag = XML_Util::createEndElement('myNs:myTag'); - * - * - * @param string $qname qualified tagname (including namespace) - * - * @return string XML end element - * @access public - * @static - * @see createStartElement(), createTag() - */ - function createEndElement($qname) - { - $element = sprintf('', $qname); - return $element; - } - - /** - * create an XML comment - * - * - * require_once 'XML/Util.php'; - * - * // create an XML start element: - * $tag = XML_Util::createComment('I am a comment'); - * - * - * @param string $content content of the comment - * - * @return string XML comment - * @access public - * @static - */ - function createComment($content) - { - $comment = sprintf('', $content); - return $comment; - } - - /** - * create a CData section - * - * - * require_once 'XML/Util.php'; - * - * // create a CData section - * $tag = XML_Util::createCDataSection('I am content.'); - * - * - * @param string $data data of the CData section - * - * @return string CData section with content - * @access public - * @static - */ - function createCDataSection($data) - { - return sprintf('', - preg_replace('/\]\]>/', ']]]]>', strval($data))); - - } - - /** - * split qualified name and return namespace and local part - * - * - * require_once 'XML/Util.php'; - * - * // split qualified tag - * $parts = XML_Util::splitQualifiedName('xslt:stylesheet'); - * - * the returned array will contain two elements: - *
    -     * array(
    -     *     'namespace' => 'xslt',
    -     *     'localPart' => 'stylesheet'
    -     * );
    -     * 
    - * - * @param string $qname qualified tag name - * @param string $defaultNs default namespace (optional) - * - * @return array array containing namespace and local part - * @access public - * @static - */ - function splitQualifiedName($qname, $defaultNs = null) - { - if (strstr($qname, ':')) { - $tmp = explode(':', $qname); - return array( - 'namespace' => $tmp[0], - 'localPart' => $tmp[1] - ); - } - return array( - 'namespace' => $defaultNs, - 'localPart' => $qname - ); - } - - /** - * check, whether string is valid XML name - * - *

    XML names are used for tagname, attribute names and various - * other, lesser known entities.

    - *

    An XML name may only consist of alphanumeric characters, - * dashes, undescores and periods, and has to start with a letter - * or an underscore.

    - * - * - * require_once 'XML/Util.php'; - * - * // verify tag name - * $result = XML_Util::isValidName('invalidTag?'); - * if (is_a($result, 'PEAR_Error')) { - * print 'Invalid XML name: ' . $result->getMessage(); - * } - * - * - * @param string $string string that should be checked - * - * @return mixed true, if string is a valid XML name, PEAR error otherwise - * @access public - * @static - * @todo support for other charsets - * @todo PEAR CS - unable to avoid 85-char limit on second preg_match - */ - function isValidName($string) - { - // check for invalid chars - if (!preg_match('/^[[:alpha:]_]\\z/', $string{0})) { - return XML_Util::raiseError('XML names may only start with letter ' - . 'or underscore', XML_UTIL_ERROR_INVALID_START); - } - - // check for invalid chars - if (!preg_match('/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?[[:alpha:]_]([[:alnum:]\_\-\.]+)?\\z/', - $string) - ) { - return XML_Util::raiseError('XML names may only contain alphanumeric ' - . 'chars, period, hyphen, colon and underscores', - XML_UTIL_ERROR_INVALID_CHARS); - } - // XML name is valid - return true; - } - - /** - * replacement for XML_Util::raiseError - * - * Avoids the necessity to always require - * PEAR.php - * - * @param string $msg error message - * @param int $code error code - * - * @return PEAR_Error - * @access public - * @static - * @todo PEAR CS - should this use include_once instead? - */ - function raiseError($msg, $code) - { - require_once 'phar://go-pear.phar/' . 'PEAR.php'; - return PEAR::raiseError($msg, $code); - } -} -?> -:”“Slc(%ÝÍ¥+ÖbC°°GBMB diff --git a/cookbooks/php/libraries/matchers.rb b/cookbooks/php/libraries/matchers.rb index 3546e5f..f79863c 100644 --- a/cookbooks/php/libraries/matchers.rb +++ b/cookbooks/php/libraries/matchers.rb @@ -16,6 +16,10 @@ if defined?(ChefSpec) ChefSpec::Matchers::ResourceMatcher.new(:php_pear, :purge, resource_name) end + def purge_php_pear(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:php_pear, :option, resource_name) + end + ChefSpec.define_matcher :php_pear_channel def discover_php_pear_channel(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:php_pear_channel, :discover, resource_name) @@ -32,4 +36,13 @@ if defined?(ChefSpec) def add_php_pear_channel(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:php_pear_channel, :add, resource_name) end + + ChefSpec.define_matcher :php_fpm_pool + def install_php_fpm_pool(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:php_fpm_pool, :install, resource_name) + end + + def uninstall_php_fpm_pool(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:php_fpm_pool, :uninstall, resource_name) + end end diff --git a/cookbooks/php/metadata.json b/cookbooks/php/metadata.json index 0f77757..734dcbe 100644 --- a/cookbooks/php/metadata.json +++ b/cookbooks/php/metadata.json @@ -1 +1 @@ -{"name":"php","version":"1.7.2","description":"Installs and maintains php and php modules","long_description":"","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@getchef.com","license":"Apache 2.0","platforms":{"debian":">= 0.0.0","ubuntu":">= 0.0.0","centos":">= 0.0.0","redhat":">= 0.0.0","fedora":">= 0.0.0","scientific":">= 0.0.0","amazon":">= 0.0.0","windows":">= 0.0.0","oracle":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","xml":">= 0.0.0","mysql":">= 6.0.0","yum-epel":">= 0.0.0","windows":">= 0.0.0","iis":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"php":"Installs php","php::package":"Installs php using packages.","php::source":"Installs php from source.","php::module_apc":"Install the php5-apc package","php::module_curl":"Install the php5-curl package","php::module_fileinfo":"Install the php5-fileinfo package","php::module_fpdf":"Install the php-fpdf package","php::module_gd":"Install the php5-gd package","php::module_ldap":"Install the php5-ldap package","php::module_memcache":"Install the php5-memcache package","php::module_mysql":"Install the php5-mysql package","php::module_pgsql":"Install the php5-pgsql packag","php::module_sqlite3":"Install the php5-sqlite3 package"}} \ No newline at end of file +{"name":"php","version":"4.2.0","description":"Installs and maintains php and php modules","long_description":"# php Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/php.svg?branch=master)](http://travis-ci.org/chef-cookbooks/php) [![Cookbook Version](https://img.shields.io/cookbook/v/php.svg)](https://supermarket.chef.io/cookbooks/php)\n\nIt installs and configures PHP and the PEAR package management system. Also includes resources for managing PEAR (and PECL) packages, PECL channels, and PHP-FPM pools.\n\n## Requirements\n\n### Platforms\n\n- Debian, Ubuntu\n- CentOS, Red Hat, Oracle, Scientific, Amazon Linux\n- Fedora\n\n### Chef\n\n- Chef 12.7+\n\n### Cookbooks\n\n- build-essential\n- xml\n- mysql\n\n## Attributes\n\n- `node['php']['install_method']` = method to install php with, default `package`.\n- `node['php']['directives']` = Hash of directives and values to append to `php.ini`, default `{}`.\n- `node['php']['pear']` = Name of the pear executable to use, default `pear`.\n\nThe file also contains the following attribute types:\n\n- platform specific locations and settings.\n- source installation settings\n\n## Resource/Provider\n\nThis cookbook includes LWRPs for managing:\n\n- PEAR channels\n- PEAR/PECL packages\n\n### `php_pear_channel`\n\n[PEAR Channels](http://pear.php.net/manual/en/guide.users.commandline.channels.php) are alternative sources for PEAR packages. This resource provides and easy way to manage these channels.\n\n#### Actions\n\n- :discover: Initialize a channel from its server.\n- :add: Add a channel to the channel list, usually only used to add private channels. Public channels are usually added using the `:discover` action\n- :update: Update an existing channel\n- :remove: Remove a channel from the List\n\n#### Attribute Parameters\n\n- channel_name: name attribute. The name of the channel to discover\n- channel_xml: the channel.xml file of the channel you are adding\n- pear: pear binary, default: pear\n\n#### Examples\n\n```ruby\n# discover the horde channel\nphp_pear_channel \"pear.horde.org\" do\n action :discover\nend\n\n# download xml then add the symfony channel\nremote_file \"#{Chef::Config[:file_cache_path]}/symfony-channel.xml\" do\n source \"http://pear.symfony-project.com/channel.xml\"\n mode 0644\nend\nphp_pear_channel \"symfony\" do\n channel_xml \"#{Chef::Config[:file_cache_path]}/symfony-channel.xml\"\n action :add\nend\n\n# update the main pear channel\nphp_pear_channel 'pear.php.net' do\n action :update\nend\n\n# update the main pecl channel\nphp_pear_channel 'pecl.php.net' do\n action :update\nend\n```\n\n### `php_pear`\n\n[PEAR](http://pear.php.net/) is a framework and distribution system for reusable PHP components. [PECL](http://pecl.php.net/) is a repository for PHP Extensions. PECL contains C extensions for compiling into PHP. As C programs, PECL extensions run more efficiently than PEAR packages. PEARs and PECLs use the same packaging and distribution system. As such this LWRP is clever enough to abstract away the small differences and can be used for managing either. This LWRP also creates the proper module .ini file for each PECL extension at the correct location for each supported platform.\n\n#### Actions\n\n- `:install`: Install a pear package - if version is provided, install that specific version\n- `:upgrade`: Upgrade a pear package - if version is provided, upgrade to that specific version\n- `:remove`: Remove a pear package\n- `:purge`: Purge a pear package (this usually entails removing configuration files as well as the package itself). With pear packages this behaves the same as `:remove`\n\n#### Attribute Parameters\n\n- `package_name`: name attribute. The name of the pear package to install\n- version: the version of the pear package to install/upgrade. If no version is given latest is assumed.\n- `preferred_state`: PEAR by default installs stable packages only, this allows you to install pear packages in a devel, alpha or beta state\n- `directives`: extra extension directives (settings) for a pecl. on most platforms these usually get rendered into the extension's .ini file\n- `zend_extensions`: extension filenames which should be loaded with zend_extension.\n- o`ptions`: Add additional options to the underlying pear package command\n\n#### Examples\n\n```ruby\n# upgrade a pear\nphp_pear \"XML_RPC\" do\n action :upgrade\nend\n\n\n# install a specific version\nphp_pear \"XML_RPC\" do\n version \"1.5.4\"\n action :install\nend\n\n\n# install the mongodb pecl\nphp_pear \"mongo\" do\n action :install\nend\n\n# install the xdebug pecl\nphp_pear \"xdebug\" do\n # Specify that xdebug.so must be loaded as a zend extension\n zend_extensions ['xdebug.so']\n action :install\nend\n\n\n# install apc pecl with directives\nphp_pear \"apc\" do\n action :install\n directives(:shm_size => 128, :enable_cli => 1)\nend\n\n\n# install the beta version of Horde_Url\n# from the horde channel\nhc = php_pear_channel \"pear.horde.org\" do\n action :discover\nend\nphp_pear \"Horde_Url\" do\n preferred_state \"beta\"\n channel hc.channel_name\n action :install\nend\n\n\n# install the YAML pear from the symfony project\nsc = php_pear_channel \"pear.symfony-project.com\" do\n action :discover\nend\nphp_pear \"YAML\" do\n channel sc.channel_name\n action :install\nend\n```\n\n### `php_fpm_pool`\n\nInstalls the `php-fpm` package appropriate for your distro (if using packages) and configures a FPM pool for you. Currently only supported in Debian-family operating systems and CentOS 7 (or at least tested with such, YMMV if you are using source).\n\nPlease consider FPM functionally pre-release, and test it thoroughly in your environment before using it in production\n\nMore info: \n\n#### Actions\n\n- `:install`: Installs the FPM pool (default).\n- `:uninstall`: Removes the FPM pool.\n\n#### Attribute Parameters\n\n- `pool_name`: name attribute. The name of the FPM pool.\n- `listen`: The listen address. Default: `/var/run/php5-fpm.sock`\n- `user`: The user to run the FPM under. Default should be the webserver user for your distro.\n- `group`: The group to run the FPM under. Default should be the webserver group for your distro.\n- `process_manager`: Process manager to use - see . Default: `dynamic`\n- `max_children`: Max children to scale to. Default: 5\n- `start_servers`: Number of servers to start the pool with. Default: 2\n- `min_spare_servers`: Minimum number of servers to have as spares. Default: 1\n- `max_spare_servers`: Maximum number of servers to have as spares. Default: 3\n- `chdir`: The startup working directory of the pool. Default: `/`\n- `additional_config`: Additional parameters in JSON. Default: {}\n\n#### Examples\n\n```ruby\n# Install a FPM pool named \"default\"\nphp_fpm_pool \"default\" do\n action :install\nend\n```\n\n## Recipes\n\n### default\n\nInclude the default recipe in a run list, to get `php`. By default `php` is installed from packages but this can be changed by using the `install_method` attribute.\n\n### package\n\nThis recipe installs PHP from packages.\n\n### source\n\nThis recipe installs PHP from source.\n\n## Deprecated Recipes\n\nThe following recipes are deprecated and will be removed from a future version of this cookbook.\n\n- `module_apc`\n- `module_apcu`\n- `module_curl`\n- `module_fileinfo`\n- `module_fpdf`\n- `module_gd`\n- `module_imap`\n- `module_ldap`\n- `module_memcache`\n- `module_mysql`\n- `module_pgsql`\n- `module_sqlite3`\n\nThe installation of the php modules in these recipes can now be accomplished by installing from a native package or via the new php_pear LWRP. For example, the functionality of the `module_memcache` recipe can be enabled in the following ways:\n\n```ruby\n# using apt\npackage \"php5-memcache\" do\n action :install\nend\n\n# using pear LWRP\nphp_pear \"memcache\" do\n action :install\nend\n```\n\n## Usage\n\nSimply include the `php` recipe where ever you would like php installed. To install from source override the `node['php']['install_method']` attribute with in a role or wrapper cookbook:\n\n### Role example:\n\n```ruby\nname \"php\"\ndescription \"Install php from source\"\noverride_attributes(\n \"php\" => {\n \"install_method\" => \"source\"\n }\n)\nrun_list(\n \"recipe[php]\"\n)\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2008-2017, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","suse":">= 0.0.0","opensuse":">= 0.0.0","opensuseleap":">= 0.0.0","ubuntu":">= 0.0.0"},"dependencies":{"build-essential":">= 0.0.0","xml":">= 0.0.0","mysql":">= 6.0.0","yum-epel":">= 0.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"php":"Installs php","php::package":"Installs php using packages.","php::source":"Installs php from source.","php::module_apc":"Install the php5-apc package","php::module_curl":"Install the php5-curl package","php::module_fileinfo":"Install the php5-fileinfo package","php::module_fpdf":"Install the php-fpdf package","php::module_gd":"Install the php5-gd package","php::module_imap":"Install the php5-imap package","php::module_ldap":"Install the php5-ldap package","php::module_memcache":"Install the php5-memcache package","php::module_mysql":"Install the php5-mysql package","php::module_pgsql":"Install the php5-pgsql packag","php::module_sqlite3":"Install the php5-sqlite3 package"},"source_url":"https://github.com/chef-cookbooks/php","issues_url":"https://github.com/chef-cookbooks/php/issues","chef_version":[[">= 12.7"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/php/providers/fpm_pool.rb b/cookbooks/php/providers/fpm_pool.rb deleted file mode 100644 index c44df54..0000000 --- a/cookbooks/php/providers/fpm_pool.rb +++ /dev/null @@ -1,86 +0,0 @@ -# -# Author:: Chris Marchesi -# Cookbook Name:: php -# Provider:: fpm_pool -# -# Copyright:: 2015, Opscode, Inc -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -def whyrun_supported? - true -end - -def install_fpm_package - # Install the FPM pacakge for this platform, if it's available - # Fail the run if it's an unsupported OS (FPM pacakge name not populated) - # also, this is skipped for source - return if node['php']['install_method'] == 'source' - - if node['php']['fpm_package'].nil? - raise 'PHP-FPM package not found (you probably have an unsupported distro)' - else - file node['php']['fpm_default_conf'] do - action :nothing - end - package node['php']['fpm_package'] do - action :install - notifies :delete, "file[#{node['php']['fpm_default_conf']}]" - end - end -end - -def register_fpm_service - service node['php']['fpm_service'] do - action :enable - end -end - -action :install do - # Ensure the FPM pacakge is installed, and the service is registered - install_fpm_package - register_fpm_service - # I wanted to have this as a function in itself, but doing this seems to - # break testing suites? - t = template "#{node['php']['fpm_pooldir']}/#{new_resource.pool_name}.conf" do - source 'fpm-pool.conf.erb' - action :create - cookbook 'php' - variables ({ - :fpm_pool_name => new_resource.pool_name, - :fpm_pool_user => new_resource.user, - :fpm_pool_group => new_resource.group, - :fpm_pool_listen => new_resource.listen, - :fpm_pool_manager => new_resource.process_manager, - :fpm_pool_max_children => new_resource.max_children, - :fpm_pool_start_servers => new_resource.start_servers, - :fpm_pool_min_spare_servers => new_resource.min_spare_servers, - :fpm_pool_max_spare_servers => new_resource.max_spare_servers, - :fpm_pool_chdir => new_resource.chdir, - :fpm_pool_additional_config => new_resource.additional_config - }) - notifies :restart, "service[#{node['php']['fpm_package']}]" - end - new_resource.updated_by_last_action(t.updated_by_last_action?) -end - -action :uninstall do - # Ensure the FPM pacakge is installed, and the service is registered - register_fpm_service - # Delete the FPM pool. - f = file "#{node['php']['fpm_pooldir']}/#{new_resource.pool_name}" do - action :delete - end - new_resource.updated_by_last_action(f.updated_by_last_action?) -end diff --git a/cookbooks/php/providers/pear.rb b/cookbooks/php/providers/pear.rb index a21715b..7e9cd04 100644 --- a/cookbooks/php/providers/pear.rb +++ b/cookbooks/php/providers/pear.rb @@ -1,9 +1,9 @@ # -# Author:: Seth Chisamore -# Cookbook Name:: php +# Author:: Seth Chisamore +# Cookbook:: php # Provider:: pear_package # -# Copyright:: 2011, Opscode, Inc +# Copyright:: 2011-2017, Chef Software, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ # limitations under the License. # +use_inline_resources + require 'chef/mixin/shell_out' require 'chef/mixin/language' include Chef::Mixin::ShellOut @@ -26,6 +28,8 @@ include Chef::Mixin::ShellOut # the Chef::Provider::Package which will make # refactoring into core chef easy +use_inline_resources + def whyrun_supported? true end @@ -41,7 +45,7 @@ action :install do info_output = "Installing #{@new_resource}" info_output << " version #{install_version}" if install_version && !install_version.empty? Chef::Log.info(info_output) - status = install_package(@new_resource.package_name, install_version) + install_package(@new_resource.package_name, install_version) end end end @@ -52,7 +56,7 @@ action :upgrade do description = "upgrade package #{@new_resource} version from #{orig_version} to #{candidate_version}" converge_by(description) do Chef::Log.info("Upgrading #{@new_resource} version from #{orig_version} to #{candidate_version}") - status = upgrade_package(@new_resource.package_name, candidate_version) + upgrade_package(@new_resource.package_name, candidate_version) end end end @@ -98,7 +102,7 @@ end # so refactoring into core Chef should be easy def load_current_resource - @current_resource = Chef::Resource::PhpPear.new(@new_resource.name) + @current_resource = new_resource.class.new(new_resource.name) @current_resource.package_name(@new_resource.package_name) @bin = node['php']['pear'] if pecl? @@ -172,14 +176,14 @@ def remove_package(name, version) end def enable_package(name) - execute "/usr/sbin/php5enmod #{name}" do - only_if { platform?('ubuntu') && node['platform_version'].to_f >= 12.04 && ::File.exist?('/usr/sbin/php5enmod') } + execute "#{node['php']['enable_mod']} #{name}" do + only_if { platform?('ubuntu') && ::File.exist?(node['php']['enable_mod']) } end end def disable_package(name) - execute "/usr/sbin/php5dismod #{name}" do - only_if { platform?('ubuntu') && node['platform_version'].to_f >= 12.04 && ::File.exist?('/usr/sbin/php5dismod') } + execute "#{node['php']['disable_mod']} #{name}" do + only_if { platform?('ubuntu') && ::File.exist?(node['php']['disable_mod']) } end end @@ -202,7 +206,7 @@ def prefix_channel(channel) channel ? "#{channel}/" : '' end -def get_extension_dir +def extension_dir @extension_dir ||= begin # Consider using "pecl config-get ext_dir". It is more cross-platform. # p = shell_out("php-config --extension-dir") @@ -223,7 +227,7 @@ def get_extension_files(name) end def manage_pecl_ini(name, action, directives, zend_extensions) - ext_prefix = get_extension_dir + ext_prefix = extension_dir ext_prefix << ::File::SEPARATOR if ext_prefix[-1].chr != ::File::SEPARATOR files = get_extension_files(name) @@ -237,7 +241,7 @@ def manage_pecl_ini(name, action, directives, zend_extensions) end ] - directory "#{node['php']['ext_conf_dir']}" do + directory node['php']['ext_conf_dir'] do owner 'root' group 'root' mode '0755' @@ -250,7 +254,7 @@ def manage_pecl_ini(name, action, directives, zend_extensions) owner 'root' group 'root' mode '0644' - variables(:name => name, :extensions => extensions, :directives => directives) + variables(name: name, extensions: extensions, directives: directives) action action end end @@ -264,13 +268,13 @@ def grep_for_version(stdout, package) # Horde_Url -n/a-/(1.0.0beta1 beta) Horde Url class # Horde_Url 1.0.0beta1 (beta) 1.0.0beta1 Horde Url class v = m.split(/\s+/)[1].strip - if v.split(/\//)[0] =~ /.\./ - # 1.1.4/(1.1.4 stable) - v = v.split(/\//)[0] - else - # -n/a-/(1.0.0beta1 beta) - v = v.split(/(.*)\/\((.*)/).last.split(/\s/)[0] - end + v = if v.split(%r{/\//})[0] =~ /.\./ + # 1.1.4/(1.1.4 stable) + v.split(%r{/\//})[0] + else + # -n/a-/(1.0.0beta1 beta) + v.split(%r{/(.*)\/\((.*)/}).last.split(/\s/)[0] + end end v end @@ -288,7 +292,7 @@ def pecl? elsif grep_for_version(shell_out(node['php']['pecl'] + search_args).stdout, @new_resource.package_name) true else - fail "Package #{@new_resource.package_name} not found in either PEAR or PECL." + raise "Package #{@new_resource.package_name} not found in either PEAR or PECL." end end end diff --git a/cookbooks/php/providers/pear_channel.rb b/cookbooks/php/providers/pear_channel.rb deleted file mode 100644 index daa4f48..0000000 --- a/cookbooks/php/providers/pear_channel.rb +++ /dev/null @@ -1,91 +0,0 @@ -# -# Author:: Seth Chisamore -# Cookbook Name:: php -# Provider:: pear_channel -# -# Copyright:: 2011, Opscode, Inc -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# http://pear.php.net/manual/en/guide.users.commandline.channels.php - -require 'chef/mixin/shell_out' -require 'chef/mixin/language' -include Chef::Mixin::ShellOut - -def whyrun_supported? - true -end - -action :discover do - unless exists? - Chef::Log.info("Discovering pear channel #{@new_resource}") - execute "#{node['php']['pear']} channel-discover #{@new_resource.channel_name}" do - action :run - end - end -end - -action :add do - unless exists? - Chef::Log.info("Adding pear channel #{@new_resource} from #{@new_resource.channel_xml}") - execute "#{node['php']['pear']} channel-add #{@new_resource.channel_xml}" do - action :run - end - end -end - -action :update do - if exists? - update_needed = false - begin - updated_needed = true if shell_out("#{node['php']['pear']} search -c #{@new_resource.channel_name} NNNNNN").stdout =~ /channel-update/ - rescue Chef::Exceptions::CommandTimeout - # CentOS can hang on 'pear search' if a channel needs updating - Chef::Log.info("Timed out checking if channel-update needed...forcing update of pear channel #{@new_resource}") - update_needed = true - end - if update_needed - description = "update pear channel #{@new_resource}" - converge_by(description) do - Chef::Log.info("Updating pear channel #{@new_resource}") - shell_out!("#{node['php']['pear']} channel-update #{@new_resource.channel_name}") - end - end - end -end - -action :remove do - if exists? - Chef::Log.info("Deleting pear channel #{@new_resource}") - execute "#{node['php']['pear']} channel-delete #{@new_resource.channel_name}" do - action :run - end - end -end - -def load_current_resource - @current_resource = Chef::Resource::PhpPearChannel.new(@new_resource.name) - @current_resource.channel_name(@new_resource.channel_name) - @current_resource -end - -private - -def exists? - shell_out!("#{node['php']['pear']} channel-info #{@current_resource.channel_name}") - true -rescue Mixlib::ShellOut::ShellCommandFailed - false -end diff --git a/cookbooks/php/recipes/default.rb b/cookbooks/php/recipes/default.rb index e94b6c4..88a6cad 100644 --- a/cookbooks/php/recipes/default.rb +++ b/cookbooks/php/recipes/default.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: default # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/php/recipes/ini.rb b/cookbooks/php/recipes/ini.rb index ee0f15e..d2d9c85 100644 --- a/cookbooks/php/recipes/ini.rb +++ b/cookbooks/php/recipes/ini.rb @@ -1,9 +1,9 @@ # # Author:: Christo De Lange () -# Cookbook Name:: php +# Cookbook:: php # Recipe:: ini # -# Copyright 2011-2014, Chef Software, Inc. +# Copyright:: 2011-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,10 +21,9 @@ template "#{node['php']['conf_dir']}/php.ini" do source node['php']['ini']['template'] cookbook node['php']['ini']['cookbook'] - unless platform?('windows') - owner 'root' - group node['root_group'] - mode '0644' - end - variables(:directives => node['php']['directives']) + owner 'root' + group node['root_group'] + mode '0644' + manage_symlink_source true + variables(directives: node['php']['directives']) end diff --git a/cookbooks/php/recipes/module_apc.rb b/cookbooks/php/recipes/module_apc.rb index a3b69ab..cb8a1eb 100644 --- a/cookbooks/php/recipes/module_apc.rb +++ b/cookbooks/php/recipes/module_apc.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_apc # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,18 +20,13 @@ # case node['platform_family'] -when 'rhel', 'fedora' - %w(httpd-devel pcre pcre-devel).each do |pkg| - package pkg do - action :install - end - end +when 'rhel', 'fedora', 'amazon' + package %w(httpd-devel pcre pcre-devel) + php_pear 'APC' do action :install - directives(:shm_size => '128M', :enable_cli => 0) + directives(shm_size: '128M', enable_cli: 0) end when 'debian' - package 'php-apc' do - action :install - end + package node['php']['apc']['package'] end diff --git a/cookbooks/php/recipes/module_apcu.rb b/cookbooks/php/recipes/module_apcu.rb new file mode 100644 index 0000000..263ceb5 --- /dev/null +++ b/cookbooks/php/recipes/module_apcu.rb @@ -0,0 +1,32 @@ +# +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php +# Recipe:: module_apc +# +# Copyright:: 2009-2017, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +case node['platform_family'] +when 'rhel', 'fedora', 'amazon' + package %w(httpd-devel pcre pcre-devel) + + php_pear 'APCu' do + action :install + directives(shm_size: '128M', enable_cli: 0) + end +when 'debian' + package node['php']['apcu']['package'] +end diff --git a/cookbooks/php/recipes/module_curl.rb b/cookbooks/php/recipes/module_curl.rb index 7fa7abd..e896a41 100644 --- a/cookbooks/php/recipes/module_curl.rb +++ b/cookbooks/php/recipes/module_curl.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_curl # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,11 +19,7 @@ # limitations under the License. # -case node['platform_family'] -when 'rhel', 'fedora' - # centos php compiled with curl -when 'debian' - package 'php5-curl' do - action :upgrade - end +package node['php']['curl']['package'] do + action :install + only_if { platform_family?('debian') } # centos php compiled with curl end diff --git a/cookbooks/php/recipes/module_fpdf.rb b/cookbooks/php/recipes/module_fpdf.rb index 673de15..5a1b0c3 100644 --- a/cookbooks/php/recipes/module_fpdf.rb +++ b/cookbooks/php/recipes/module_fpdf.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_fpdf # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ # case node['platform_family'] -when 'rhel', 'fedora' +when 'rhel', 'fedora', 'amazon' pearhub_chan = php_pear_channel 'pearhub.org' do action :discover end diff --git a/cookbooks/php/recipes/module_gd.rb b/cookbooks/php/recipes/module_gd.rb index 4236389..9bb1082 100644 --- a/cookbooks/php/recipes/module_gd.rb +++ b/cookbooks/php/recipes/module_gd.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_gd # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,13 +21,12 @@ pkg = value_for_platform( %w(centos redhat scientific fedora amazon oracle) => { - el5_range => 'php53-gd', - 'default' => 'php-gd' + 'default' => 'php-gd', }, 'freebsd' => { - 'default' => 'php56-gd' + 'default' => 'php56-gd', }, - 'default' => 'php5-gd' + 'default' => node['php']['gd']['package'] ) package pkg do diff --git a/cookbooks/php/libraries/helpers.rb b/cookbooks/php/recipes/module_imap.rb similarity index 67% rename from cookbooks/php/libraries/helpers.rb rename to cookbooks/php/recipes/module_imap.rb index 24d9fcb..c5853aa 100644 --- a/cookbooks/php/libraries/helpers.rb +++ b/cookbooks/php/recipes/module_imap.rb @@ -1,9 +1,7 @@ # -# Author:: Joshua Timberman () -# Cookbook Name:: php -# Libraries:: helpers -# -# Copyright 2013, Opscode, Inc. +# Author:: Artur Melo () +# Cookbook:: php +# Recipe:: module_imap # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,6 +16,13 @@ # limitations under the License. # -def el5_range - (0..99).to_a.map { |i| "5.#{i}" } +pkg = value_for_platform( + %w(centos redhat scientific fedora amazon oracle) => { + 'default' => 'php-imap', + }, + 'default' => 'php5-imap' +) + +package pkg do + action :install end diff --git a/cookbooks/php/recipes/module_ldap.rb b/cookbooks/php/recipes/module_ldap.rb index 0b8e8bf..0555948 100644 --- a/cookbooks/php/recipes/module_ldap.rb +++ b/cookbooks/php/recipes/module_ldap.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_ldap # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,10 +21,9 @@ pkg = value_for_platform( %w(centos redhat scientific fedora amazon oracle) => { - el5_range => 'php53-ldap', - 'default' => 'php-ldap' + 'default' => 'php-ldap', }, - 'default' => 'php5-ldap' + 'default' => node['php']['ldap']['package'] ) package pkg do diff --git a/cookbooks/php/recipes/module_memcache.rb b/cookbooks/php/recipes/module_memcache.rb index 4c05266..5f79573 100644 --- a/cookbooks/php/recipes/module_memcache.rb +++ b/cookbooks/php/recipes/module_memcache.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_memcache # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,18 +20,12 @@ # case node['platform_family'] -when 'rhel', 'fedora' - %w(zlib-devel).each do |pkg| - package pkg do - action :install - end - end +when 'rhel', 'fedora', 'amazon' + package 'zlib-devel' + php_pear 'memcache' do action :install - # directives(:shm_size => "128M", :enable_cli => 0) end when 'debian' - package 'php5-memcache' do - action :install - end + package 'php5-memcache' end diff --git a/cookbooks/php/recipes/module_mysql.rb b/cookbooks/php/recipes/module_mysql.rb index 7b7d2ab..b8a87c5 100644 --- a/cookbooks/php/recipes/module_mysql.rb +++ b/cookbooks/php/recipes/module_mysql.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_mysql # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/php/recipes/module_pgsql.rb b/cookbooks/php/recipes/module_pgsql.rb index f7837d8..95318a6 100644 --- a/cookbooks/php/recipes/module_pgsql.rb +++ b/cookbooks/php/recipes/module_pgsql.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_pgsql # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,10 +21,9 @@ pkg = value_for_platform( %w(centos redhat scientific fedora amazon oracle) => { - el5_range => 'php53-pgsql', - 'default' => 'php-pgsql' + 'default' => 'php-pgsql', }, - 'default' => 'php5-pgsql' + 'default' => node['php']['pgsql']['package'] ) package pkg do diff --git a/cookbooks/php/recipes/module_sqlite3.rb b/cookbooks/php/recipes/module_sqlite3.rb index 5d887c1..10ee38f 100644 --- a/cookbooks/php/recipes/module_sqlite3.rb +++ b/cookbooks/php/recipes/module_sqlite3.rb @@ -1,10 +1,10 @@ # -# Author:: Joshua Timberman () -# Author:: Seth Chisamore () -# Cookbook Name:: php +# Author:: Joshua Timberman () +# Author:: Seth Chisamore () +# Cookbook:: php # Recipe:: module_sqlite3 # -# Copyright 2009-2014, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,11 +19,7 @@ # limitations under the License. # -case node['platform_family'] -when 'rhel', 'fedora' - # already there in centos, --with-pdo-sqlite=shared -when 'debian' - package 'php5-sqlite' do - action :install - end +package node['php']['sqlite']['package'] do + action :install + only_if { platform_family?('debian') } # already there in centos, --with-pdo-sqlite=shared end diff --git a/cookbooks/php/recipes/package.rb b/cookbooks/php/recipes/package.rb index 06799ef..b077ff5 100644 --- a/cookbooks/php/recipes/package.rb +++ b/cookbooks/php/recipes/package.rb @@ -1,10 +1,10 @@ # -# Author:: Seth Chisamore () -# Author:: Lucas Hansen () -# Cookbook Name:: php +# Author:: Seth Chisamore () +# Author:: Lucas Hansen () +# Cookbook:: php # Recipe:: package # -# Copyright 2013-2014, Chef Software, Inc. +# Copyright:: 2013-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,45 +19,13 @@ # limitations under the License. # -if platform?('windows') - - include_recipe 'iis::mod_cgi' - - install_dir = File.expand_path(node['php']['conf_dir']).gsub('/', '\\') - windows_package node['php']['windows']['msi_name'] do - source node['php']['windows']['msi_source'] - installer_type :msi - - options %W( - /quiet - INSTALLDIR="#{install_dir}" - ADDLOCAL=#{node['php']['packages'].join(',')} - ).join(' ') +if platform_family?('rhel', 'debian', 'amazon', 'suse') + package node['php']['packages'] do + options node['php']['package_options'] end - - # WARNING: This is not the out-of-the-box go-pear.phar. It's been modified to patch this bug: - # http://pear.php.net/bugs/bug.php?id=16644 - cookbook_file "#{node['php']['conf_dir']}/PEAR/go-pear.phar" do - source 'go-pear.phar' - end - - template "#{node['php']['conf_dir']}/pear-options" do - source 'pear-options.erb' - end - - execute 'install-pear' do - cwd node['php']['conf_dir'] - command 'go-pear.bat < pear-options' - creates "#{node['php']['conf_dir']}/pear.bat" - end - - ENV['PATH'] += ";#{install_dir}" - windows_path install_dir - else node['php']['packages'].each do |pkg| package pkg do - action :install options node['php']['package_options'] end end diff --git a/cookbooks/php/recipes/recompile.rb b/cookbooks/php/recipes/recompile.rb index 1a090cd..4137bc0 100644 --- a/cookbooks/php/recipes/recompile.rb +++ b/cookbooks/php/recipes/recompile.rb @@ -1,9 +1,9 @@ # # Author:: David Kinzer () -# Cookbook Name:: php +# Cookbook:: php # Recipe:: recompile # -# Copyright 2014, David Kinzer +# Copyright:: 2014-2017, David Kinzer # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ end bash 'un-pack php' do cwd Chef::Config[:file_cache_path] code "tar -zxf php-#{version}.tar.gz" - creates "#{node['php']['url']}/php-#{version}" + creates "#{Chef::Config[:file_cache_path]}/php-#{version}" end bash 're-build php' do @@ -46,6 +46,6 @@ bash 're-build php' do code <<-EOF (make clean) (#{ext_dir_prefix} ./configure #{configure_options}) - (make && make install) + (make -j #{node['cpu']['total']} && make install) EOF end diff --git a/cookbooks/php/recipes/source.rb b/cookbooks/php/recipes/source.rb index 9825911..257aaa2 100644 --- a/cookbooks/php/recipes/source.rb +++ b/cookbooks/php/recipes/source.rb @@ -1,9 +1,9 @@ # -# Author:: Seth Chisamore () -# Cookbook Name:: php -# Recipe:: package +# Author:: Seth Chisamore () +# Cookbook:: php +# Recipe:: source # -# Copyright 2011-2014, Chef Software, Inc. +# Copyright:: 2011-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,11 +29,7 @@ mysql_client 'default' do only_if { configure_options =~ /mysql/ } end -node['php']['src_deps'].each do |pkg| - package pkg do - action :install - end -end +package node['php']['src_deps'] version = node['php']['version'] @@ -41,7 +37,7 @@ remote_file "#{Chef::Config[:file_cache_path]}/php-#{version}.tar.gz" do source "#{node['php']['url']}/php-#{version}.tar.gz/from/this/mirror" checksum node['php']['checksum'] mode '0644' - not_if "which #{node['php']['bin']}" + not_if "$(which #{node['php']['bin']}) --version | grep #{version}" end if node['php']['ext_dir'] @@ -56,14 +52,21 @@ else ext_dir_prefix = '' end +# PHP is unable to find the GMP library in 16.04. The symlink brings the file +# inside of the include libraries. +link '/usr/include/gmp.h' do + to '/usr/include/x86_64-linux-gnu/gmp.h' + only_if { node['platform_family'] == 'debian' && node['platform_version'].to_f >= 14.04 } +end + bash 'build php' do cwd Chef::Config[:file_cache_path] code <<-EOF tar -zxf php-#{version}.tar.gz (cd php-#{version} && #{ext_dir_prefix} ./configure #{configure_options}) - (cd php-#{version} && make && make install) + (cd php-#{version} && make -j #{node['cpu']['total']} && make install) EOF - not_if "which #{node['php']['bin']}" + not_if "$(which #{node['php']['bin']}) --version | grep #{version}" end directory node['php']['conf_dir'] do diff --git a/cookbooks/php/resources/fpm_pool.rb b/cookbooks/php/resources/fpm_pool.rb index 0a6c6ab..1b1a40e 100644 --- a/cookbooks/php/resources/fpm_pool.rb +++ b/cookbooks/php/resources/fpm_pool.rb @@ -1,9 +1,9 @@ # # Author:: Chris Marchesi -# Cookbook Name:: php +# Cookbook:: php # Resource:: fpm_pool # -# Copyright:: 2015, Opscode, Inc +# Copyright:: 2015-2017, Chef Software, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,17 +18,80 @@ # limitations under the License. # -default_action :install -actions :install, :uninstall +property :pool_name, String, name_property: true +property :listen, String, default: lazy { node['php']['fpm_socket'] } +property :user, String, default: lazy { node['php']['fpm_user'] } +property :group, String, default: lazy { node['php']['fpm_group'] } +property :listen_user, String, default: lazy { node['php']['fpm_listen_user'] } +property :listen_group, String, default: lazy { node['php']['fpm_listen_group'] } +property :process_manager, String, default: 'dynamic' +property :max_children, Integer, default: 5 +property :start_servers, Integer, default: 2 +property :min_spare_servers, Integer, default: 1 +property :max_spare_servers, Integer, default: 3 +property :chdir, String, default: '/' +property :additional_config, Hash, default: {} -attribute :pool_name, :kind_of => String, :name_attribute => true -attribute :listen, :default => '/var/run/php5-fpm.sock' -attribute :user, :kind_of => String, :default => node['php']['fpm_user'] -attribute :group, :kind_of => String, :default => node['php']['fpm_user'] -attribute :process_manager, :kind_of => String, :default => 'dynamic' -attribute :max_children, :kind_of => Integer, :default => 5 -attribute :start_servers, :kind_of => Integer, :default => 2 -attribute :min_spare_servers, :kind_of => Integer, :default => 1 -attribute :max_spare_servers, :kind_of => Integer, :default => 3 -attribute :chdir, :kind_of => String, :default => '/' -attribute :additional_config, :kind_of => Hash, :default => {} +action :install do + # Ensure the FPM pacakge is installed, and the service is registered + install_fpm_package + register_fpm_service + # I wanted to have this as a function in itself, but doing this seems to + # break testing suites? + template "#{node['php']['fpm_pooldir']}/#{new_resource.pool_name}.conf" do + source 'fpm-pool.conf.erb' + action :create + cookbook 'php' + variables( + fpm_pool_name: new_resource.pool_name, + fpm_pool_user: new_resource.user, + fpm_pool_group: new_resource.group, + fpm_pool_listen: new_resource.listen, + fpm_pool_listen_user: new_resource.listen_user, + fpm_pool_listen_group: new_resource.listen_group, + fpm_pool_manager: new_resource.process_manager, + fpm_pool_max_children: new_resource.max_children, + fpm_pool_start_servers: new_resource.start_servers, + fpm_pool_min_spare_servers: new_resource.min_spare_servers, + fpm_pool_max_spare_servers: new_resource.max_spare_servers, + fpm_pool_chdir: new_resource.chdir, + fpm_pool_additional_config: new_resource.additional_config + ) + notifies :restart, "service[#{node['php']['fpm_service']}]" + end +end + +action :uninstall do + # Ensure the FPM pacakge is installed, and the service is registered + register_fpm_service + # Delete the FPM pool. + file "#{node['php']['fpm_pooldir']}/#{new_resource.pool_name}.conf" do + action :delete + end +end + +action_class do + def install_fpm_package + # Install the FPM pacakge for this platform, if it's available + # Fail the run if it's an unsupported OS (FPM pacakge name not populated) + # also, this is skipped for source + return if node['php']['install_method'] == 'source' + + raise 'PHP-FPM package not found (you probably have an unsupported distro)' if node['php']['fpm_package'].nil? + + file node['php']['fpm_default_conf'] do + action :nothing + end + + package node['php']['fpm_package'] do + action :install + notifies :delete, "file[#{node['php']['fpm_default_conf']}]", :immediately + end + end + + def register_fpm_service + service node['php']['fpm_service'] do + action :enable + end + end +end diff --git a/cookbooks/php/resources/pear.rb b/cookbooks/php/resources/pear.rb index 9052393..287489b 100644 --- a/cookbooks/php/resources/pear.rb +++ b/cookbooks/php/resources/pear.rb @@ -1,9 +1,9 @@ # -# Author:: Seth Chisamore -# Cookbook Name:: php +# Author:: Seth Chisamore +# Cookbook:: php # Resource:: pear_package # -# Copyright:: 2011-2014, Chef Software, Inc +# Copyright:: 2011-2016, Chef Software, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,10 +29,10 @@ state_attrs :channel, :version, :zend_extensions -attribute :package_name, :kind_of => String, :name_attribute => true -attribute :version, :default => nil -attribute :channel, :kind_of => String -attribute :options, :kind_of => String -attribute :directives, :kind_of => Hash, :default => {} -attribute :zend_extensions, :kind_of => Array, :default => [] -attribute :preferred_state, :default => 'stable' +attribute :package_name, kind_of: String, name_attribute: true +attribute :version, default: nil +attribute :channel, kind_of: String +attribute :options, kind_of: String +attribute :directives, kind_of: Hash, default: {} +attribute :zend_extensions, kind_of: Array, default: [] +attribute :preferred_state, default: 'stable' diff --git a/cookbooks/php/resources/pear_channel.rb b/cookbooks/php/resources/pear_channel.rb index 33c33f9..188453a 100644 --- a/cookbooks/php/resources/pear_channel.rb +++ b/cookbooks/php/resources/pear_channel.rb @@ -1,9 +1,10 @@ # -# Author:: Seth Chisamore -# Cookbook Name:: php +# Author:: Seth Chisamore +# Author:: Jennifer Davis +# Cookbook:: php # Resource:: pear_channel # -# Copyright:: 2011-2014, Chef Software, Inc +# Copyright:: 2011-2017, Chef Software, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,15 +19,65 @@ # limitations under the License. # -default_action :discover -actions :discover, :add, :update, :remove - -state_attrs :channel_name, - :channel_xml - -attribute :channel_name, :kind_of => String, :name_attribute => true -attribute :channel_xml, :kind_of => String - +property :channel_xml, kind_of: String +property :channel_name, kind_of: String, name_property: true +property :pear, kind_of: String, default: lazy { node['php']['pear'] } # TODO: add authenticated channel support! -# attribute :username, :kind_of => String -# attribute :password, :kind_of => String +# property :username, :kind_of => String +# property :password, :kind_of => String + +action :discover do + unless exists? + Chef::Log.info("Discovering pear channel #{new_resource}") + execute "#{new_resource.pear} channel-discover #{new_resource.channel_name}" do + action :run + end + end +end + +action :add do + unless exists? + Chef::Log.info("Adding pear channel #{new_resource} from #{new_resource.channel_xml}") + execute "#{new_resource.pear} channel-add #{new_resource.channel_xml}" do + action :run + end + end +end + +action :update do + if exists? + update_needed = false + begin + update_needed = true if shell_out("#{new_resource.pear} search -c #{new_resource.channel_name} NNNNNN").stdout =~ /channel-update/ + rescue Chef::Exceptions::CommandTimeout + # CentOS can hang on 'pear search' if a channel needs updating + Chef::Log.info("Timed out checking if channel-update needed...forcing update of pear channel #{new_resource}") + update_needed = true + end + if update_needed + description = "update pear channel #{new_resource}" + converge_by(description) do + Chef::Log.info("Updating pear channel #{new_resource}") + shell_out!("#{new_resource.pear} channel-update #{new_resource.channel_name}") + end + end + end +end + +action :remove do + if exists? + Chef::Log.info("Deleting pear channel #{new_resource}") + execute "#{new_resource.pear} channel-delete #{new_resource.channel_name}" do + action :run + end + end +end + +action_class do + def exists? + shell_out!("#{new_resource.pear} channel-info #{new_resource.channel_name}") + true + rescue Mixlib::ShellOut::ShellCommandFailed + false + end +end diff --git a/cookbooks/php/templates/default/fpm-pool.conf.erb b/cookbooks/php/templates/default/fpm-pool.conf.erb index aa01b8f..71ad207 100644 --- a/cookbooks/php/templates/default/fpm-pool.conf.erb +++ b/cookbooks/php/templates/default/fpm-pool.conf.erb @@ -2,8 +2,8 @@ user = <%= @fpm_pool_user %> group = <%= @fpm_pool_group %> listen = <%= @fpm_pool_listen %> -listen.owner = <%= @fpm_pool_user %> -listen.group = <%= @fpm_pool_group %> +listen.owner = <%= @fpm_pool_listen_user %> +listen.group = <%= @fpm_pool_listen_group %> pm = <%= @fpm_pool_manager %> pm.max_children = <%= @fpm_pool_max_children %> pm.start_servers = <%= @fpm_pool_start_servers %> diff --git a/cookbooks/php/templates/windows/pear-options.erb b/cookbooks/php/templates/windows/pear-options.erb deleted file mode 100644 index 7f9405c..0000000 --- a/cookbooks/php/templates/windows/pear-options.erb +++ /dev/null @@ -1,18 +0,0 @@ - -all - - - - - - - - - - - -<%= node['php']['conf_dir'].gsub("/", "\\") %> - -n - - diff --git a/cookbooks/php/templates/windows/php.ini.erb b/cookbooks/php/templates/windows/php.ini.erb deleted file mode 100644 index 0a0caaa..0000000 --- a/cookbooks/php/templates/windows/php.ini.erb +++ /dev/null @@ -1,1935 +0,0 @@ -[PHP] - -;;;;;;;;;;;;;;;;;;; -; About php.ini ; -;;;;;;;;;;;;;;;;;;; -; PHP's initialization file, generally called php.ini, is responsible for -; configuring many of the aspects of PHP's behavior. - -; PHP attempts to find and load this configuration from a number of locations. -; The following is a summary of its search order: -; 1. SAPI module specific location. -; 2. The PHPRC environment variable. (As of PHP 5.2.0) -; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) -; 4. Current working directory (except CLI) -; 5. The web server's directory (for SAPI modules), or directory of PHP -; (otherwise in Windows) -; 6. The directory from the --with-config-file-path compile time option, or the -; Windows directory (C:\windows or C:\winnt) -; See the PHP docs for more specific information. -; http://php.net/configuration.file - -; The syntax of the file is extremely simple. Whitespace and lines -; beginning with a semicolon are silently ignored (as you probably guessed). -; Section headers (e.g. [Foo]) are also silently ignored, even though -; they might mean something in the future. - -; Directives following the section heading [PATH=/www/mysite] only -; apply to PHP files in the /www/mysite directory. Directives -; following the section heading [HOST=www.example.com] only apply to -; PHP files served from www.example.com. Directives set in these -; special sections cannot be overridden by user-defined INI files or -; at runtime. Currently, [PATH=] and [HOST=] sections only work under -; CGI/FastCGI. -; http://php.net/ini.sections - -; Directives are specified using the following syntax: -; directive = value -; Directive names are *case sensitive* - foo=bar is different from FOO=bar. -; Directives are variables used to configure PHP or PHP extensions. -; There is no name validation. If PHP can't find an expected -; directive because it is not set or is mistyped, a default value will be used. - -; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one -; of the INI constants (On, Off, True, False, Yes, No and None) or an expression -; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a -; previously set variable or directive (e.g. ${foo}) - -; Expressions in the INI file are limited to bitwise operators and parentheses: -; | bitwise OR -; ^ bitwise XOR -; & bitwise AND -; ~ bitwise NOT -; ! boolean NOT - -; Boolean flags can be turned on using the values 1, On, True or Yes. -; They can be turned off using the values 0, Off, False or No. - -; An empty string can be denoted by simply not writing anything after the equal -; sign, or by using the None keyword: - -; foo = ; sets foo to an empty string -; foo = None ; sets foo to an empty string -; foo = "None" ; sets foo to the string 'None' - -; If you use constants in your value, and these constants belong to a -; dynamically loaded extension (either a PHP extension or a Zend extension), -; you may only use these constants *after* the line that loads the extension. - -;;;;;;;;;;;;;;;;;;; -; About this file ; -;;;;;;;;;;;;;;;;;;; -; PHP comes packaged with two INI files. One that is recommended to be used -; in production environments and one that is recommended to be used in -; development environments. - -; php.ini-production contains settings which hold security, performance and -; best practices at its core. But please be aware, these settings may break -; compatibility with older or less security conscience applications. We -; recommending using the production ini in production and testing environments. - -; php.ini-development is very similar to its production variant, except it's -; much more verbose when it comes to errors. We recommending using the -; development version only in development environments as errors shown to -; application users can inadvertently leak otherwise secure information. - -;;;;;;;;;;;;;;;;;;; -; Quick Reference ; -;;;;;;;;;;;;;;;;;;; -; The following are all the settings which are different in either the production -; or development versions of the INIs with respect to PHP's default behavior. -; Please see the actual settings later in the document for more details as to why -; we recommend these changes in PHP's behavior. - -; allow_call_time_pass_reference -; Default Value: On -; Development Value: Off -; Production Value: Off - -; display_errors -; Default Value: On -; Development Value: On -; Production Value: Off - -; display_startup_errors -; Default Value: Off -; Development Value: On -; Production Value: Off - -; error_reporting -; Default Value: E_ALL & ~E_NOTICE -; Development Value: E_ALL | E_STRICT -; Production Value: E_ALL & ~E_DEPRECATED - -; html_errors -; Default Value: On -; Development Value: On -; Production value: Off - -; log_errors -; Default Value: Off -; Development Value: On -; Production Value: On - -; magic_quotes_gpc -; Default Value: On -; Development Value: Off -; Production Value: Off - -; max_input_time -; Default Value: -1 (Unlimited) -; Development Value: 60 (60 seconds) -; Production Value: 60 (60 seconds) - -; output_buffering -; Default Value: Off -; Development Value: 4096 -; Production Value: 4096 - -; register_argc_argv -; Default Value: On -; Development Value: Off -; Production Value: Off - -; register_long_arrays -; Default Value: On -; Development Value: Off -; Production Value: Off - -; request_order -; Default Value: None -; Development Value: "GP" -; Production Value: "GP" - -; session.bug_compat_42 -; Default Value: On -; Development Value: On -; Production Value: Off - -; session.bug_compat_warn -; Default Value: On -; Development Value: On -; Production Value: Off - -; session.gc_divisor -; Default Value: 100 -; Development Value: 1000 -; Production Value: 1000 - -; session.hash_bits_per_character -; Default Value: 4 -; Development Value: 5 -; Production Value: 5 - -; short_open_tag -; Default Value: On -; Development Value: Off -; Production Value: Off - -; track_errors -; Default Value: Off -; Development Value: On -; Production Value: Off - -; url_rewriter.tags -; Default Value: "a=href,area=href,frame=src,form=,fieldset=" -; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" -; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" - -; variables_order -; Default Value: "EGPCS" -; Development Value: "GPCS" -; Production Value: "GPCS" - -;;;;;;;;;;;;;;;;;;;; -; php.ini Options ; -;;;;;;;;;;;;;;;;;;;; -; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" -;user_ini.filename = ".user.ini" - -; To disable this feature set this option to empty value -;user_ini.filename = - -; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) -;user_ini.cache_ttl = 300 - -;;;;;;;;;;;;;;;;;;;; -; Language Options ; -;;;;;;;;;;;;;;;;;;;; - -; Enable the PHP scripting language engine under Apache. -; http://php.net/engine -engine = On - -; This directive determines whether or not PHP will recognize code between -; tags as PHP source which should be processed as such. It's been -; recommended for several years that you not use the short tag "short cut" and -; instead to use the full tag combination. With the wide spread use -; of XML and use of these tags by other languages, the server can become easily -; confused and end up parsing the wrong code in the wrong context. But because -; this short cut has been a feature for such a long time, it's currently still -; supported for backwards compatibility, but we recommend you don't use them. -; Default Value: On -; Development Value: Off -; Production Value: Off -; http://php.net/short-open-tag -short_open_tag = Off - -; Allow ASP-style <%% %> tags. -; http://php.net/asp-tags -asp_tags = Off - -; The number of significant digits displayed in floating point numbers. -; http://php.net/precision -precision = 14 - -; Enforce year 2000 compliance (will cause problems with non-compliant browsers) -; http://php.net/y2k-compliance -y2k_compliance = On - -; Output buffering is a mechanism for controlling how much output data -; (excluding headers and cookies) PHP should keep internally before pushing that -; data to the client. If your application's output exceeds this setting, PHP -; will send that data in chunks of roughly the size you specify. -; Turning on this setting and managing its maximum buffer size can yield some -; interesting side-effects depending on your application and web server. -; You may be able to send headers and cookies after you've already sent output -; through print or echo. You also may see performance benefits if your server is -; emitting less packets due to buffered output versus PHP streaming the output -; as it gets it. On production servers, 4096 bytes is a good setting for performance -; reasons. -; Note: Output buffering can also be controlled via Output Buffering Control -; functions. -; Possible Values: -; On = Enabled and buffer is unlimited. (Use with caution) -; Off = Disabled -; Integer = Enables the buffer and sets its maximum size in bytes. -; Note: This directive is hardcoded to Off for the CLI SAPI -; Default Value: Off -; Development Value: 4096 -; Production Value: 4096 -; http://php.net/output-buffering -output_buffering = 4096 - -; You can redirect all of the output of your scripts to a function. For -; example, if you set output_handler to "mb_output_handler", character -; encoding will be transparently converted to the specified encoding. -; Setting any output handler automatically turns on output buffering. -; Note: People who wrote portable scripts should not depend on this ini -; directive. Instead, explicitly set the output handler using ob_start(). -; Using this ini directive may cause problems unless you know what script -; is doing. -; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler" -; and you cannot use both "ob_gzhandler" and "zlib.output_compression". -; Note: output_handler must be empty if this is set 'On' !!!! -; Instead you must use zlib.output_handler. -; http://php.net/output-handler -;output_handler = - -; Transparent output compression using the zlib library -; Valid values for this option are 'off', 'on', or a specific buffer size -; to be used for compression (default is 4KB) -; Note: Resulting chunk size may vary due to nature of compression. PHP -; outputs chunks that are few hundreds bytes each as a result of -; compression. If you prefer a larger chunk size for better -; performance, enable output_buffering in addition. -; Note: You need to use zlib.output_handler instead of the standard -; output_handler, or otherwise the output will be corrupted. -; http://php.net/zlib.output-compression -zlib.output_compression = Off - -; http://php.net/zlib.output-compression-level -;zlib.output_compression_level = -1 - -; You cannot specify additional output handlers if zlib.output_compression -; is activated here. This setting does the same as output_handler but in -; a different order. -; http://php.net/zlib.output-handler -;zlib.output_handler = - -; Implicit flush tells PHP to tell the output layer to flush itself -; automatically after every output block. This is equivalent to calling the -; PHP function flush() after each and every call to print() or echo() and each -; and every HTML block. Turning this option on has serious performance -; implications and is generally recommended for debugging purposes only. -; http://php.net/implicit-flush -; Note: This directive is hardcoded to On for the CLI SAPI -implicit_flush = Off - -; The unserialize callback function will be called (with the undefined class' -; name as parameter), if the unserializer finds an undefined class -; which should be instantiated. A warning appears if the specified function is -; not defined, or if the function doesn't include/implement the missing class. -; So only set this entry, if you really want to implement such a -; callback-function. -unserialize_callback_func = - -; When floats & doubles are serialized store serialize_precision significant -; digits after the floating point. The default value ensures that when floats -; are decoded with unserialize, the data will remain the same. -serialize_precision = 17 - -; This directive allows you to enable and disable warnings which PHP will issue -; if you pass a value by reference at function call time. Passing values by -; reference at function call time is a deprecated feature which will be removed -; from PHP at some point in the near future. The acceptable method for passing a -; value by reference to a function is by declaring the reference in the functions -; definition, not at call time. This directive does not disable this feature, it -; only determines whether PHP will warn you about it or not. These warnings -; should enabled in development environments only. -; Default Value: On (Suppress warnings) -; Development Value: Off (Issue warnings) -; Production Value: Off (Issue warnings) -; http://php.net/allow-call-time-pass-reference -allow_call_time_pass_reference = Off - -; Safe Mode -; http://php.net/safe-mode -safe_mode = Off - -; By default, Safe Mode does a UID compare check when -; opening files. If you want to relax this to a GID compare, -; then turn on safe_mode_gid. -; http://php.net/safe-mode-gid -safe_mode_gid = Off - -; When safe_mode is on, UID/GID checks are bypassed when -; including files from this directory and its subdirectories. -; (directory must also be in include_path or full path must -; be used when including) -; http://php.net/safe-mode-include-dir -safe_mode_include_dir = - -; When safe_mode is on, only executables located in the safe_mode_exec_dir -; will be allowed to be executed via the exec family of functions. -; http://php.net/safe-mode-exec-dir -safe_mode_exec_dir = - -; Setting certain environment variables may be a potential security breach. -; This directive contains a comma-delimited list of prefixes. In Safe Mode, -; the user may only alter environment variables whose names begin with the -; prefixes supplied here. By default, users will only be able to set -; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR). -; Note: If this directive is empty, PHP will let the user modify ANY -; environment variable! -; http://php.net/safe-mode-allowed-env-vars -safe_mode_allowed_env_vars = PHP_ - -; This directive contains a comma-delimited list of environment variables that -; the end user won't be able to change using putenv(). These variables will be -; protected even if safe_mode_allowed_env_vars is set to allow to change them. -; http://php.net/safe-mode-protected-env-vars -safe_mode_protected_env_vars = LD_LIBRARY_PATH - -; open_basedir, if set, limits all file operations to the defined directory -; and below. This directive makes most sense if used in a per-directory -; or per-virtualhost web server configuration file. This directive is -; *NOT* affected by whether Safe Mode is turned On or Off. -; http://php.net/open-basedir -;open_basedir = - -; This directive allows you to disable certain functions for security reasons. -; It receives a comma-delimited list of function names. This directive is -; *NOT* affected by whether Safe Mode is turned On or Off. -; http://php.net/disable-functions -disable_functions = - -; This directive allows you to disable certain classes for security reasons. -; It receives a comma-delimited list of class names. This directive is -; *NOT* affected by whether Safe Mode is turned On or Off. -; http://php.net/disable-classes -disable_classes = - -; Colors for Syntax Highlighting mode. Anything that's acceptable in -; would work. -; http://php.net/syntax-highlighting -;highlight.string = #DD0000 -;highlight.comment = #FF9900 -;highlight.keyword = #007700 -;highlight.bg = #FFFFFF -;highlight.default = #0000BB -;highlight.html = #000000 - -; If enabled, the request will be allowed to complete even if the user aborts -; the request. Consider enabling it if executing long requests, which may end up -; being interrupted by the user or a browser timing out. PHP's default behavior -; is to disable this feature. -; http://php.net/ignore-user-abort -;ignore_user_abort = On - -; Determines the size of the realpath cache to be used by PHP. This value should -; be increased on systems where PHP opens many files to reflect the quantity of -; the file operations performed. -; http://php.net/realpath-cache-size -;realpath_cache_size = 16k - -; Duration of time, in seconds for which to cache realpath information for a given -; file or directory. For systems with rarely changing files, consider increasing this -; value. -; http://php.net/realpath-cache-ttl -;realpath_cache_ttl = 120 - -; Enables or disables the circular reference collector. -; http://php.net/zend.enable-gc -zend.enable_gc = On - -;;;;;;;;;;;;;;;;; -; Miscellaneous ; -;;;;;;;;;;;;;;;;; - -; Decides whether PHP may expose the fact that it is installed on the server -; (e.g. by adding its signature to the Web server header). It is no security -; threat in any way, but it makes it possible to determine whether you use PHP -; on your server or not. -; http://php.net/expose-php -expose_php = On - -;;;;;;;;;;;;;;;;;;; -; Resource Limits ; -;;;;;;;;;;;;;;;;;;; - -; Maximum execution time of each script, in seconds -; http://php.net/max-execution-time -; Note: This directive is hardcoded to 0 for the CLI SAPI -max_execution_time =300 - -; Maximum amount of time each script may spend parsing request data. It's a good -; idea to limit this time on productions servers in order to eliminate unexpectedly -; long running scripts. -; Note: This directive is hardcoded to -1 for the CLI SAPI -; Default Value: -1 (Unlimited) -; Development Value: 60 (60 seconds) -; Production Value: 60 (60 seconds) -; http://php.net/max-input-time -max_input_time = 60 - -; Maximum input variable nesting level -; http://php.net/max-input-nesting-level -;max_input_nesting_level = 64 - -; How many GET/POST/COOKIE input variables may be accepted -; max_input_vars = 1000 - -; Maximum amount of memory a script may consume (128MB) -; http://php.net/memory-limit -memory_limit = 128M - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Error handling and logging ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; This directive informs PHP of which errors, warnings and notices you would like -; it to take action for. The recommended way of setting values for this -; directive is through the use of the error level constants and bitwise -; operators. The error level constants are below here for convenience as well as -; some common settings and their meanings. -; By default, PHP is set to take action on all errors, notices and warnings EXCEPT -; those related to E_NOTICE and E_STRICT, which together cover best practices and -; recommended coding standards in PHP. For performance reasons, this is the -; recommend error reporting setting. Your production server shouldn't be wasting -; resources complaining about best practices and coding standards. That's what -; development servers and development settings are for. -; Note: The php.ini-development file has this setting as E_ALL | E_STRICT. This -; means it pretty much reports everything which is exactly what you want during -; development and early testing. -; -; Error Level Constants: -; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) -; E_ERROR - fatal run-time errors -; E_RECOVERABLE_ERROR - almost fatal run-time errors -; E_WARNING - run-time warnings (non-fatal errors) -; E_PARSE - compile-time parse errors -; E_NOTICE - run-time notices (these are warnings which often result -; from a bug in your code, but it's possible that it was -; intentional (e.g., using an uninitialized variable and -; relying on the fact it's automatically initialized to an -; empty string) -; E_STRICT - run-time notices, enable to have PHP suggest changes -; to your code which will ensure the best interoperability -; and forward compatibility of your code -; E_CORE_ERROR - fatal errors that occur during PHP's initial startup -; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's -; initial startup -; E_COMPILE_ERROR - fatal compile-time errors -; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) -; E_USER_ERROR - user-generated error message -; E_USER_WARNING - user-generated warning message -; E_USER_NOTICE - user-generated notice message -; E_DEPRECATED - warn about code that will not work in future versions -; of PHP -; E_USER_DEPRECATED - user-generated deprecation warnings -; -; Common Values: -; E_ALL & ~E_NOTICE (Show all errors, except for notices and coding standards warnings.) -; E_ALL & ~E_NOTICE | E_STRICT (Show all errors, except for notices) -; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) -; E_ALL | E_STRICT (Show all errors, warnings and notices including coding standards.) -; Default Value: E_ALL & ~E_NOTICE -; Development Value: E_ALL | E_STRICT -; Production Value: E_ALL & ~E_DEPRECATED -; http://php.net/error-reporting -error_reporting = E_ALL & ~E_DEPRECATED - -; This directive controls whether or not and where PHP will output errors, -; notices and warnings too. Error output is very useful during development, but -; it could be very dangerous in production environments. Depending on the code -; which is triggering the error, sensitive information could potentially leak -; out of your application such as database usernames and passwords or worse. -; It's recommended that errors be logged on production servers rather than -; having the errors sent to STDOUT. -; Possible Values: -; Off = Do not display any errors -; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) -; On or stdout = Display errors to STDOUT -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/display-errors -display_errors = Off - -; The display of errors which occur during PHP's startup sequence are handled -; separately from display_errors. PHP's default behavior is to suppress those -; errors from clients. Turning the display of startup errors on can be useful in -; debugging configuration problems. But, it's strongly recommended that you -; leave this setting off on production servers. -; Default Value: Off -; Development Value: On -; Production Value: Off -; http://php.net/display-startup-errors -display_startup_errors = Off - -; Besides displaying errors, PHP can also log errors to locations such as a -; server-specific log, STDERR, or a location specified by the error_log -; directive found below. While errors should not be displayed on productions -; servers they should still be monitored and logging is a great way to do that. -; Default Value: Off -; Development Value: On -; Production Value: On -; http://php.net/log-errors -log_errors =On - -; Set maximum length of log_errors. In error_log information about the source is -; added. The default is 1024 and 0 allows to not apply any maximum length at all. -; http://php.net/log-errors-max-len -log_errors_max_len = 1024 - -; Do not log repeated messages. Repeated errors must occur in same file on same -; line unless ignore_repeated_source is set true. -; http://php.net/ignore-repeated-errors -ignore_repeated_errors = Off - -; Ignore source of message when ignoring repeated messages. When this setting -; is On you will not log errors with repeated messages from different files or -; source lines. -; http://php.net/ignore-repeated-source -ignore_repeated_source = Off - -; If this parameter is set to Off, then memory leaks will not be shown (on -; stdout or in the log). This has only effect in a debug compile, and if -; error reporting includes E_WARNING in the allowed list -; http://php.net/report-memleaks -report_memleaks = On - -; This setting is on by default. -;report_zend_debug = 0 - -; Store the last error/warning message in $php_errormsg (boolean). Setting this value -; to On can assist in debugging and is appropriate for development servers. It should -; however be disabled on production servers. -; Default Value: Off -; Development Value: On -; Production Value: Off -; http://php.net/track-errors -track_errors = Off - -; Turn off normal error reporting and emit XML-RPC error XML -; http://php.net/xmlrpc-errors -;xmlrpc_errors = 0 - -; An XML-RPC faultCode -;xmlrpc_error_number = 0 - -; When PHP displays or logs an error, it has the capability of inserting html -; links to documentation related to that error. This directive controls whether -; those HTML links appear in error messages or not. For performance and security -; reasons, it's recommended you disable this on production servers. -; Note: This directive is hardcoded to Off for the CLI SAPI -; Default Value: On -; Development Value: On -; Production value: Off -; http://php.net/html-errors -html_errors = Off - -; If html_errors is set On PHP produces clickable error messages that direct -; to a page describing the error or function causing the error in detail. -; You can download a copy of the PHP manual from http://php.net/docs -; and change docref_root to the base URL of your local copy including the -; leading '/'. You must also specify the file extension being used including -; the dot. PHP's default behavior is to leave these settings empty. -; Note: Never use this feature for production boxes. -; http://php.net/docref-root -; Examples -;docref_root = "/phpmanual/" - -; http://php.net/docref-ext -;docref_ext = .html - -; String to output before an error message. PHP's default behavior is to leave -; this setting blank. -; http://php.net/error-prepend-string -; Example: -;error_prepend_string = "" - -; String to output after an error message. PHP's default behavior is to leave -; this setting blank. -; http://php.net/error-append-string -; Example: -;error_append_string = "" - -; Log errors to specified file. PHP's default behavior is to leave this value -; empty. -; http://php.net/error-log -; Example: -;error_log = php_errors.log -; Log errors to syslog (Event Log on NT, not valid in Windows 95). -;error_log = syslog - -;windows.show_crt_warning -; Default value: 0 -; Development value: 0 -; Production value: 0 - -;;;;;;;;;;;;;;;;; -; Data Handling ; -;;;;;;;;;;;;;;;;; - -; The separator used in PHP generated URLs to separate arguments. -; PHP's default setting is "&". -; http://php.net/arg-separator.output -; Example: -;arg_separator.output = "&" - -; List of separator(s) used by PHP to parse input URLs into variables. -; PHP's default setting is "&". -; NOTE: Every character in this directive is considered as separator! -; http://php.net/arg-separator.input -; Example: -;arg_separator.input = ";&" - -; This directive determines which super global arrays are registered when PHP -; starts up. If the register_globals directive is enabled, it also determines -; what order variables are populated into the global space. G,P,C,E & S are -; abbreviations for the following respective super globals: GET, POST, COOKIE, -; ENV and SERVER. There is a performance penalty paid for the registration of -; these arrays and because ENV is not as commonly used as the others, ENV is -; is not recommended on productions servers. You can still get access to -; the environment variables through getenv() should you need to. -; Default Value: "EGPCS" -; Development Value: "GPCS" -; Production Value: "GPCS"; -; http://php.net/variables-order -variables_order = "GPCS" - -; This directive determines which super global data (G,P,C,E & S) should -; be registered into the super global array REQUEST. If so, it also determines -; the order in which that data is registered. The values for this directive are -; specified in the same manner as the variables_order directive, EXCEPT one. -; Leaving this value empty will cause PHP to use the value set in the -; variables_order directive. It does not mean it will leave the super globals -; array REQUEST empty. -; Default Value: None -; Development Value: "GP" -; Production Value: "GP" -; http://php.net/request-order -request_order = "GP" - -; Whether or not to register the EGPCS variables as global variables. You may -; want to turn this off if you don't want to clutter your scripts' global scope -; with user data. -; You should do your best to write your scripts so that they do not require -; register_globals to be on; Using form variables as globals can easily lead -; to possible security problems, if the code is not very well thought of. -; http://php.net/register-globals -register_globals = Off - -; Determines whether the deprecated long $HTTP_*_VARS type predefined variables -; are registered by PHP or not. As they are deprecated, we obviously don't -; recommend you use them. They are on by default for compatibility reasons but -; they are not recommended on production servers. -; Default Value: On -; Development Value: Off -; Production Value: Off -; http://php.net/register-long-arrays -register_long_arrays = Off - -; This directive determines whether PHP registers $argv & $argc each time it -; runs. $argv contains an array of all the arguments passed to PHP when a script -; is invoked. $argc contains an integer representing the number of arguments -; that were passed when the script was invoked. These arrays are extremely -; useful when running scripts from the command line. When this directive is -; enabled, registering these variables consumes CPU cycles and memory each time -; a script is executed. For performance reasons, this feature should be disabled -; on production servers. -; Note: This directive is hardcoded to On for the CLI SAPI -; Default Value: On -; Development Value: Off -; Production Value: Off -; http://php.net/register-argc-argv -register_argc_argv = Off - -; When enabled, the SERVER and ENV variables are created when they're first -; used (Just In Time) instead of when the script starts. If these variables -; are not used within a script, having this directive on will result in a -; performance gain. The PHP directives register_globals, register_long_arrays, -; and register_argc_argv must be disabled for this directive to have any affect. -; http://php.net/auto-globals-jit -auto_globals_jit = On - -; Maximum size of POST data that PHP will accept. -; http://php.net/post-max-size -post_max_size = 8M - -; Magic quotes are a preprocessing feature of PHP where PHP will attempt to -; escape any character sequences in GET, POST, COOKIE and ENV data which might -; otherwise corrupt data being placed in resources such as databases before -; making that data available to you. Because of character encoding issues and -; non-standard SQL implementations across many databases, it's not currently -; possible for this feature to be 100% accurate. PHP's default behavior is to -; enable the feature. We strongly recommend you use the escaping mechanisms -; designed specifically for the database your using instead of relying on this -; feature. Also note, this feature has been deprecated as of PHP 5.3.0 and is -; scheduled removed in PHP 5.4. -; Default Value: On -; Development Value: Off -; Production Value: Off -; http://php.net/magic-quotes-gpc -magic_quotes_gpc = Off - -; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. -; http://php.net/magic-quotes-runtime -magic_quotes_runtime = Off - -; Use Sybase-style magic quotes (escape ' with '' instead of \'). -; http://php.net/magic-quotes-sybase -magic_quotes_sybase = Off - -; Automatically add files before PHP document. -; http://php.net/auto-prepend-file -auto_prepend_file = - -; Automatically add files after PHP document. -; http://php.net/auto-append-file -auto_append_file = - -; By default, PHP will output a character encoding using -; the Content-type: header. To disable sending of the charset, simply -; set it to be empty. -; -; PHP's built-in default is text/html -; http://php.net/default-mimetype -default_mimetype = "text/html" - -; PHP's default character set is set to empty. -; http://php.net/default-charset -;default_charset = "iso-8859-1" - -; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is -; to disable this feature. -; http://php.net/always-populate-raw-post-data -;always_populate_raw_post_data = On - -;;;;;;;;;;;;;;;;;;;;;;;;; -; Paths and Directories ; -;;;;;;;;;;;;;;;;;;;;;;;;; - -; UNIX: "/path1:/path2" -;include_path = ".:/php/includes" -; -; Windows: "\path1;\path2" -;include_path = ".;c:\php\includes" -; -; PHP's default setting for include_path is ".;/path/to/php/pear" -; http://php.net/include-path - -; The root of the PHP pages, used only if nonempty. -; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root -; if you are running php as a CGI under any web server (other than IIS) -; see documentation for security issues. The alternate is to use the -; cgi.force_redirect configuration below -; http://php.net/doc-root -doc_root = - -; The directory under which PHP opens the script using /~username used only -; if nonempty. -; http://php.net/user-dir -user_dir = - -; Directory in which the loadable extensions (modules) reside. -; http://php.net/extension-dir -; extension_dir = "./" -; On windows: -; extension_dir = "ext" - -; Whether or not to enable the dl() function. The dl() function does NOT work -; properly in multithreaded servers, such as IIS or Zeus, and is automatically -; disabled on them. -; http://php.net/enable-dl -enable_dl = Off - -; cgi.force_redirect is necessary to provide security running PHP as a CGI under -; most web servers. Left undefined, PHP turns this on by default. You can -; turn it off here AT YOUR OWN RISK -; **You CAN safely turn this off for IIS, in fact, you MUST.** -; http://php.net/cgi.force-redirect -;cgi.force_redirect = 1 - -; if cgi.nph is enabled it will force cgi to always sent Status: 200 with -; every request. PHP's default behavior is to disable this feature. -;cgi.nph = 1 - -; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape -; (iPlanet) web servers, you MAY need to set an environment variable name that PHP -; will look for to know it is OK to continue execution. Setting this variable MAY -; cause security issues, KNOW WHAT YOU ARE DOING FIRST. -; http://php.net/cgi.redirect-status-env -;cgi.redirect_status_env = - -; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's -; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok -; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting -; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting -; of zero causes PHP to behave as before. Default is 1. You should fix your scripts -; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. -; http://php.net/cgi.fix-pathinfo -;cgi.fix_pathinfo=1 - -; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate -; security tokens of the calling client. This allows IIS to define the -; security context that the request runs under. mod_fastcgi under Apache -; does not currently support this feature (03/17/2002) -; Set to 1 if running under IIS. Default is zero. -; http://php.net/fastcgi.impersonate -;fastcgi.impersonate = 1 - -; Disable logging through FastCGI connection. PHP's default behavior is to enable -; this feature. -;fastcgi.logging = 0 - -; cgi.rfc2616_headers configuration option tells PHP what type of headers to -; use when sending HTTP response code. If it's set 0 PHP sends Status: header that -; is supported by Apache. When this option is set to 1 PHP will send -; RFC2616 compliant header. -; Default is zero. -; http://php.net/cgi.rfc2616-headers -;cgi.rfc2616_headers = 0 - -;;;;;;;;;;;;;;;; -; File Uploads ; -;;;;;;;;;;;;;;;; - -; Whether to allow HTTP file uploads. -; http://php.net/file-uploads -file_uploads = On - -; Temporary directory for HTTP uploaded files (will use system default if not -; specified). -; http://php.net/upload-tmp-dir -;upload_tmp_dir = - -; Maximum allowed size for uploaded files. -; http://php.net/upload-max-filesize -upload_max_filesize = 2M - -; Maximum number of files that can be uploaded via a single request -max_file_uploads = 20 - -;;;;;;;;;;;;;;;;;; -; Fopen wrappers ; -;;;;;;;;;;;;;;;;;; - -; Whether to allow the treatment of URLs (like http:// or ftp://) as files. -; http://php.net/allow-url-fopen -allow_url_fopen = On - -; Whether to allow include/require to open URLs (like http:// or ftp://) as files. -; http://php.net/allow-url-include -allow_url_include = Off - -; Define the anonymous ftp password (your email address). PHP's default setting -; for this is empty. -; http://php.net/from -;from="john@doe.com" - -; Define the User-Agent string. PHP's default setting for this is empty. -; http://php.net/user-agent -;user_agent="PHP" - -; Default timeout for socket based streams (seconds) -; http://php.net/default-socket-timeout -default_socket_timeout = 60 -upload_tmp_dir="C:\Windows\Temp" -session.save_path="C:\Windows\Temp" -error_log="C:\Windows\temp\php-errors.log" -cgi.force_redirect=0 -fastcgi.impersonate=1 -fastcgi.logging=0 -extension_dir="ext" - -; If your scripts have to deal with files from Macintosh systems, -; or you are running on a Mac and need to deal with files from -; unix or win32 systems, setting this flag will cause PHP to -; automatically detect the EOL character in those files so that -; fgets() and file() will work regardless of the source of the file. -; http://php.net/auto-detect-line-endings -;auto_detect_line_endings = Off - -;;;;;;;;;;;;;;;;;;;;;; -; Dynamic Extensions ; -;;;;;;;;;;;;;;;;;;;;;; - -; If you wish to have an extension loaded automatically, use the following -; syntax: -; -; extension=modulename.extension -; -; For example, on Windows: -; -; extension=msql.dll -; -; ... or under UNIX: -; -; extension=msql.so -; -; ... or with a path: -; -; extension=/path/to/extension/msql.so -; -; If you only provide the name of the extension, PHP will look for it in its -; default extension directory. -; -; Windows Extensions -; Note that ODBC support is built in, so no dll is needed for it. -; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5) -; extension folders as well as the separate PECL DLL download (PHP 5). -; Be sure to appropriately set the extension_dir directive. -; - -; The MIBS data available in the PHP distribution must be installed. -; See http://www.php.net/manual/en/snmp.installation.php - - -;;;;;;;;;;;;;;;;;;; -; Module Settings ; -;;;;;;;;;;;;;;;;;;; - -[Date] -; Defines the default timezone used by the date functions -; http://php.net/date.timezone -;date.timezone = - -; http://php.net/date.default-latitude -;date.default_latitude = 31.7667 - -; http://php.net/date.default-longitude -;date.default_longitude = 35.2333 - -; http://php.net/date.sunrise-zenith -;date.sunrise_zenith = 90.583333 - -; http://php.net/date.sunset-zenith -;date.sunset_zenith = 90.583333 - -[filter] -; http://php.net/filter.default -;filter.default = unsafe_raw - -; http://php.net/filter.default-flags -;filter.default_flags = - -[iconv] -;iconv.input_encoding = ISO-8859-1 -;iconv.internal_encoding = ISO-8859-1 -;iconv.output_encoding = ISO-8859-1 - -[intl] -;intl.default_locale = -; This directive allows you to produce PHP errors when some error -; happens within intl functions. The value is the level of the error produced. -; Default is 0, which does not produce any errors. -;intl.error_level = E_WARNING - -[sqlite] -; http://php.net/sqlite.assoc-case -;sqlite.assoc_case = 0 - -[sqlite3] -;sqlite3.extension_dir = - -[Pcre] -;PCRE library backtracking limit. -; http://php.net/pcre.backtrack-limit -;pcre.backtrack_limit=100000 - -;PCRE library recursion limit. -;Please note that if you set this value to a high number you may consume all -;the available process stack and eventually crash PHP (due to reaching the -;stack size limit imposed by the Operating System). -; http://php.net/pcre.recursion-limit -;pcre.recursion_limit=100000 - -[Pdo] -; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" -; http://php.net/pdo-odbc.connection-pooling -;pdo_odbc.connection_pooling=strict - -;pdo_odbc.db2_instance_name - -[Pdo_mysql] -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/pdo_mysql.cache_size -pdo_mysql.cache_size = 2000 - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/pdo_mysql.default-socket -pdo_mysql.default_socket= - -[Phar] -; http://php.net/phar.readonly -;phar.readonly = On - -; http://php.net/phar.require-hash -;phar.require_hash = On - -;phar.cache_list = - -[Syslog] -; Whether or not to define the various syslog variables (e.g. $LOG_PID, -; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In -; runtime, you can define these variables by calling define_syslog_variables(). -; http://php.net/define-syslog-variables -define_syslog_variables = Off - -[mail function] -; For Win32 only. -; http://php.net/smtp -SMTP = localhost -; http://php.net/smtp-port -smtp_port = 25 - -; For Win32 only. -; http://php.net/sendmail-from -;sendmail_from = me@example.com - -; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). -; http://php.net/sendmail-path -;sendmail_path = - -; Force the addition of the specified parameters to be passed as extra parameters -; to the sendmail binary. These parameters will always replace the value of -; the 5th parameter to mail(), even in safe mode. -;mail.force_extra_parameters = - -; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename -mail.add_x_header = On - -; The path to a log file that will log all mail() calls. Log entries include -; the full path of the script, line number, To address and headers. -;mail.log = - -[SQL] -; http://php.net/sql.safe-mode -sql.safe_mode = Off - -[ODBC] -; http://php.net/odbc.default-db -;odbc.default_db = Not yet implemented - -; http://php.net/odbc.default-user -;odbc.default_user = Not yet implemented - -; http://php.net/odbc.default-pw -;odbc.default_pw = Not yet implemented - -; Controls the ODBC cursor model. -; Default: SQL_CURSOR_STATIC (default). -;odbc.default_cursortype - -; Allow or prevent persistent links. -; http://php.net/odbc.allow-persistent -odbc.allow_persistent = On - -; Check that a connection is still valid before reuse. -; http://php.net/odbc.check-persistent -odbc.check_persistent = On - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/odbc.max-persistent -odbc.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -; http://php.net/odbc.max-links -odbc.max_links = -1 - -; Handling of LONG fields. Returns number of bytes to variables. 0 means -; passthru. -; http://php.net/odbc.defaultlrl -odbc.defaultlrl = 4096 - -; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. -; See the documentation on odbc_binmode and odbc_longreadlen for an explanation -; of odbc.defaultlrl and odbc.defaultbinmode -; http://php.net/odbc.defaultbinmode -odbc.defaultbinmode = 1 - -;birdstep.max_links = -1 - -[Interbase] -; Allow or prevent persistent links. -ibase.allow_persistent = 1 - -; Maximum number of persistent links. -1 means no limit. -ibase.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -ibase.max_links = -1 - -; Default database name for ibase_connect(). -;ibase.default_db = - -; Default username for ibase_connect(). -;ibase.default_user = - -; Default password for ibase_connect(). -;ibase.default_password = - -; Default charset for ibase_connect(). -;ibase.default_charset = - -; Default timestamp format. -ibase.timestampformat = "%Y-%m-%d %H:%M:%S" - -; Default date format. -ibase.dateformat = "%Y-%m-%d" - -; Default time format. -ibase.timeformat = "%H:%M:%S" - -[MySQL] -; Allow accessing, from PHP's perspective, local files with LOAD DATA statements -; http://php.net/mysql.allow_local_infile -mysql.allow_local_infile = On - -; Allow or prevent persistent links. -; http://php.net/mysql.allow-persistent -mysql.allow_persistent = On - -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/mysql.cache_size -mysql.cache_size = 2000 - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/mysql.max-persistent -mysql.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -; http://php.net/mysql.max-links -mysql.max_links = -1 - -; Default port number for mysql_connect(). If unset, mysql_connect() will use -; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the -; compile-time value defined MYSQL_PORT (in that order). Win32 will only look -; at MYSQL_PORT. -; http://php.net/mysql.default-port -mysql.default_port = - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/mysql.default-socket -mysql.default_socket = - -; Default host for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysql.default-host -mysql.default_host = - -; Default user for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysql.default-user -mysql.default_user = - -; Default password for mysql_connect() (doesn't apply in safe mode). -; Note that this is generally a *bad* idea to store passwords in this file. -; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password") -; and reveal this password! And of course, any users with read access to this -; file will be able to reveal the password as well. -; http://php.net/mysql.default-password -mysql.default_password = - -; Maximum time (in seconds) for connect timeout. -1 means no limit -; http://php.net/mysql.connect-timeout -mysql.connect_timeout = 60 - -; Trace mode. When trace_mode is active (=On), warnings for table/index scans and -; SQL-Errors will be displayed. -; http://php.net/mysql.trace-mode -mysql.trace_mode = Off - -[MySQLi] - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/mysqli.max-persistent -mysqli.max_persistent = -1 - -; Allow accessing, from PHP's perspective, local files with LOAD DATA statements -; http://php.net/mysqli.allow_local_infile -;mysqli.allow_local_infile = On - -; Allow or prevent persistent links. -; http://php.net/mysqli.allow-persistent -mysqli.allow_persistent = On - -; Maximum number of links. -1 means no limit. -; http://php.net/mysqli.max-links -mysqli.max_links = -1 - -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/mysqli.cache_size -mysqli.cache_size = 2000 - -; Default port number for mysqli_connect(). If unset, mysqli_connect() will use -; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the -; compile-time value defined MYSQL_PORT (in that order). Win32 will only look -; at MYSQL_PORT. -; http://php.net/mysqli.default-port -mysqli.default_port = 3306 - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/mysqli.default-socket -mysqli.default_socket = - -; Default host for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysqli.default-host -mysqli.default_host = - -; Default user for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysqli.default-user -mysqli.default_user = - -; Default password for mysqli_connect() (doesn't apply in safe mode). -; Note that this is generally a *bad* idea to store passwords in this file. -; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") -; and reveal this password! And of course, any users with read access to this -; file will be able to reveal the password as well. -; http://php.net/mysqli.default-pw -mysqli.default_pw = - -; Allow or prevent reconnect -mysqli.reconnect = Off - -[mysqlnd] -; Enable / Disable collection of general statistics by mysqlnd which can be -; used to tune and monitor MySQL operations. -; http://php.net/mysqlnd.collect_statistics -mysqlnd.collect_statistics = On - -; Enable / Disable collection of memory usage statistics by mysqlnd which can be -; used to tune and monitor MySQL operations. -; http://php.net/mysqlnd.collect_memory_statistics -mysqlnd.collect_memory_statistics = Off - -; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. -; http://php.net/mysqlnd.net_cmd_buffer_size -;mysqlnd.net_cmd_buffer_size = 2048 - -; Size of a pre-allocated buffer used for reading data sent by the server in -; bytes. -; http://php.net/mysqlnd.net_read_buffer_size -;mysqlnd.net_read_buffer_size = 32768 - -[OCI8] - -; Connection: Enables privileged connections using external -; credentials (OCI_SYSOPER, OCI_SYSDBA) -; http://php.net/oci8.privileged-connect -;oci8.privileged_connect = Off - -; Connection: The maximum number of persistent OCI8 connections per -; process. Using -1 means no limit. -; http://php.net/oci8.max-persistent -;oci8.max_persistent = -1 - -; Connection: The maximum number of seconds a process is allowed to -; maintain an idle persistent connection. Using -1 means idle -; persistent connections will be maintained forever. -; http://php.net/oci8.persistent-timeout -;oci8.persistent_timeout = -1 - -; Connection: The number of seconds that must pass before issuing a -; ping during oci_pconnect() to check the connection validity. When -; set to 0, each oci_pconnect() will cause a ping. Using -1 disables -; pings completely. -; http://php.net/oci8.ping-interval -;oci8.ping_interval = 60 - -; Connection: Set this to a user chosen connection class to be used -; for all pooled server requests with Oracle 11g Database Resident -; Connection Pooling (DRCP). To use DRCP, this value should be set to -; the same string for all web servers running the same application, -; the database pool must be configured, and the connection string must -; specify to use a pooled server. -;oci8.connection_class = - -; High Availability: Using On lets PHP receive Fast Application -; Notification (FAN) events generated when a database node fails. The -; database must also be configured to post FAN events. -;oci8.events = Off - -; Tuning: This option enables statement caching, and specifies how -; many statements to cache. Using 0 disables statement caching. -; http://php.net/oci8.statement-cache-size -;oci8.statement_cache_size = 20 - -; Tuning: Enables statement prefetching and sets the default number of -; rows that will be fetched automatically after statement execution. -; http://php.net/oci8.default-prefetch -;oci8.default_prefetch = 100 - -; Compatibility. Using On means oci_close() will not close -; oci_connect() and oci_new_connect() connections. -; http://php.net/oci8.old-oci-close-semantics -;oci8.old_oci_close_semantics = Off - -[PostgreSQL] -; Allow or prevent persistent links. -; http://php.net/pgsql.allow-persistent -pgsql.allow_persistent = On - -; Detect broken persistent links always with pg_pconnect(). -; Auto reset feature requires a little overheads. -; http://php.net/pgsql.auto-reset-persistent -pgsql.auto_reset_persistent = Off - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/pgsql.max-persistent -pgsql.max_persistent = -1 - -; Maximum number of links (persistent+non persistent). -1 means no limit. -; http://php.net/pgsql.max-links -pgsql.max_links = -1 - -; Ignore PostgreSQL backends Notice message or not. -; Notice message logging require a little overheads. -; http://php.net/pgsql.ignore-notice -pgsql.ignore_notice = 0 - -; Log PostgreSQL backends Notice message or not. -; Unless pgsql.ignore_notice=0, module cannot log notice message. -; http://php.net/pgsql.log-notice -pgsql.log_notice = 0 - -[Sybase-CT] -; Allow or prevent persistent links. -; http://php.net/sybct.allow-persistent -sybct.allow_persistent = On - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/sybct.max-persistent -sybct.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -; http://php.net/sybct.max-links -sybct.max_links = -1 - -; Minimum server message severity to display. -; http://php.net/sybct.min-server-severity -sybct.min_server_severity = 10 - -; Minimum client message severity to display. -; http://php.net/sybct.min-client-severity -sybct.min_client_severity = 10 - -; Set per-context timeout -; http://php.net/sybct.timeout -;sybct.timeout= - -;sybct.packet_size - -; The maximum time in seconds to wait for a connection attempt to succeed before returning failure. -; Default: one minute -;sybct.login_timeout= - -; The name of the host you claim to be connecting from, for display by sp_who. -; Default: none -;sybct.hostname= - -; Allows you to define how often deadlocks are to be retried. -1 means "forever". -; Default: 0 -;sybct.deadlock_retry_count= - -[bcmath] -; Number of decimal digits for all bcmath functions. -; http://php.net/bcmath.scale -bcmath.scale = 0 - -[browscap] -; http://php.net/browscap -;browscap = extra/browscap.ini - -[Session] -; Handler used to store/retrieve data. -; http://php.net/session.save-handler -session.save_handler = files - -; Argument passed to save_handler. In the case of files, this is the path -; where data files are stored. Note: Windows users have to change this -; variable in order to use PHP's session functions. -; -; The path can be defined as: -; -; session.save_path = "N;/path" -; -; where N is an integer. Instead of storing all the session files in -; /path, what this will do is use subdirectories N-levels deep, and -; store the session data in those directories. This is useful if you -; or your OS have problems with lots of files in one directory, and is -; a more efficient layout for servers that handle lots of sessions. -; -; NOTE 1: PHP will not create this directory structure automatically. -; You can use the script in the ext/session dir for that purpose. -; NOTE 2: See the section on garbage collection below if you choose to -; use subdirectories for session storage -; -; The file storage module creates files using mode 600 by default. -; You can change that by using -; -; session.save_path = "N;MODE;/path" -; -; where MODE is the octal representation of the mode. Note that this -; does not overwrite the process's umask. -; http://php.net/session.save-path -;session.save_path = "/tmp" - -; Whether to use cookies. -; http://php.net/session.use-cookies -session.use_cookies = 1 - -; http://php.net/session.cookie-secure -;session.cookie_secure = - -; This option forces PHP to fetch and use a cookie for storing and maintaining -; the session id. We encourage this operation as it's very helpful in combating -; session hijacking when not specifying and managing your own session id. It is -; not the end all be all of session hijacking defense, but it's a good start. -; http://php.net/session.use-only-cookies -session.use_only_cookies = 1 - -; Name of the session (used as cookie name). -; http://php.net/session.name -session.name = PHPSESSID - -; Initialize session on request startup. -; http://php.net/session.auto-start -session.auto_start = 0 - -; Lifetime in seconds of cookie or, if 0, until browser is restarted. -; http://php.net/session.cookie-lifetime -session.cookie_lifetime = 0 - -; The path for which the cookie is valid. -; http://php.net/session.cookie-path -session.cookie_path = / - -; The domain for which the cookie is valid. -; http://php.net/session.cookie-domain -session.cookie_domain = - -; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. -; http://php.net/session.cookie-httponly -session.cookie_httponly = - -; Handler used to serialize data. php is the standard serializer of PHP. -; http://php.net/session.serialize-handler -session.serialize_handler = php - -; Defines the probability that the 'garbage collection' process is started -; on every session initialization. The probability is calculated by using -; gc_probability/gc_divisor. Where session.gc_probability is the numerator -; and gc_divisor is the denominator in the equation. Setting this value to 1 -; when the session.gc_divisor value is 100 will give you approximately a 1% chance -; the gc will run on any give request. -; Default Value: 1 -; Development Value: 1 -; Production Value: 1 -; http://php.net/session.gc-probability -session.gc_probability = 1 - -; Defines the probability that the 'garbage collection' process is started on every -; session initialization. The probability is calculated by using the following equation: -; gc_probability/gc_divisor. Where session.gc_probability is the numerator and -; session.gc_divisor is the denominator in the equation. Setting this value to 1 -; when the session.gc_divisor value is 100 will give you approximately a 1% chance -; the gc will run on any give request. Increasing this value to 1000 will give you -; a 0.1% chance the gc will run on any give request. For high volume production servers, -; this is a more efficient approach. -; Default Value: 100 -; Development Value: 1000 -; Production Value: 1000 -; http://php.net/session.gc-divisor -session.gc_divisor = 1000 - -; After this number of seconds, stored data will be seen as 'garbage' and -; cleaned up by the garbage collection process. -; http://php.net/session.gc-maxlifetime -session.gc_maxlifetime = 1440 - -; NOTE: If you are using the subdirectory option for storing session files -; (see session.save_path above), then garbage collection does *not* -; happen automatically. You will need to do your own garbage -; collection through a shell script, cron entry, or some other method. -; For example, the following script would is the equivalent of -; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): -; find /path/to/sessions -cmin +24 | xargs rm - -; PHP 4.2 and less have an undocumented feature/bug that allows you to -; to initialize a session variable in the global scope, even when register_globals -; is disabled. PHP 4.3 and later will warn you, if this feature is used. -; You can disable the feature and the warning separately. At this time, -; the warning is only displayed, if bug_compat_42 is enabled. This feature -; introduces some serious security problems if not handled correctly. It's -; recommended that you do not use this feature on production servers. But you -; should enable this on development servers and enable the warning as well. If you -; do not enable the feature on development servers, you won't be warned when it's -; used and debugging errors caused by this can be difficult to track down. -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/session.bug-compat-42 -session.bug_compat_42 = Off - -; This setting controls whether or not you are warned by PHP when initializing a -; session value into the global space. session.bug_compat_42 must be enabled before -; these warnings can be issued by PHP. See the directive above for more information. -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/session.bug-compat-warn -session.bug_compat_warn = Off - -; Check HTTP Referer to invalidate externally stored URLs containing ids. -; HTTP_REFERER has to contain this substring for the session to be -; considered as valid. -; http://php.net/session.referer-check -session.referer_check = - -; How many bytes to read from the file. -; http://php.net/session.entropy-length -session.entropy_length = 0 - -; Specified here to create the session id. -; http://php.net/session.entropy-file -; On systems that don't have /dev/urandom /dev/arandom can be used -; On windows, setting the entropy_length setting will activate the -; Windows random source (using the CryptoAPI) -;session.entropy_file = /dev/urandom - -; Set to {nocache,private,public,} to determine HTTP caching aspects -; or leave this empty to avoid sending anti-caching headers. -; http://php.net/session.cache-limiter -session.cache_limiter = nocache - -; Document expires after n minutes. -; http://php.net/session.cache-expire -session.cache_expire = 180 - -; trans sid support is disabled by default. -; Use of trans sid may risk your users security. -; Use this option with caution. -; - User may send URL contains active session ID -; to other person via. email/irc/etc. -; - URL that contains active session ID may be stored -; in publicly accessible computer. -; - User may access your site with the same session ID -; always using URL stored in browser's history or bookmarks. -; http://php.net/session.use-trans-sid -session.use_trans_sid = 0 - -; Select a hash function for use in generating session ids. -; Possible Values -; 0 (MD5 128 bits) -; 1 (SHA-1 160 bits) -; This option may also be set to the name of any hash function supported by -; the hash extension. A list of available hashes is returned by the hash_algos() -; function. -; http://php.net/session.hash-function -session.hash_function = 0 - -; Define how many bits are stored in each character when converting -; the binary hash data to something readable. -; Possible values: -; 4 (4 bits: 0-9, a-f) -; 5 (5 bits: 0-9, a-v) -; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") -; Default Value: 4 -; Development Value: 5 -; Production Value: 5 -; http://php.net/session.hash-bits-per-character -session.hash_bits_per_character = 5 - -; The URL rewriter will look for URLs in a defined set of HTML tags. -; form/fieldset are special; if you include them here, the rewriter will -; add a hidden field with the info which is otherwise appended -; to URLs. If you want XHTML conformity, remove the form entry. -; Note that all valid entries require a "=", even if no value follows. -; Default Value: "a=href,area=href,frame=src,form=,fieldset=" -; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" -; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" -; http://php.net/url-rewriter.tags -url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" - -[MSSQL] -; Allow or prevent persistent links. -mssql.allow_persistent = On - -; Maximum number of persistent links. -1 means no limit. -mssql.max_persistent = -1 - -; Maximum number of links (persistent+non persistent). -1 means no limit. -mssql.max_links = -1 - -; Minimum error severity to display. -mssql.min_error_severity = 10 - -; Minimum message severity to display. -mssql.min_message_severity = 10 - -; Compatibility mode with old versions of PHP 3.0. -mssql.compatability_mode = Off - -; Connect timeout -;mssql.connect_timeout = 5 - -; Query timeout -;mssql.timeout = 60 - -; Valid range 0 - 2147483647. Default = 4096. -;mssql.textlimit = 4096 - -; Valid range 0 - 2147483647. Default = 4096. -;mssql.textsize = 4096 - -; Limits the number of records in each batch. 0 = all records in one batch. -;mssql.batchsize = 0 - -; Specify how datetime and datetim4 columns are returned -; On => Returns data converted to SQL server settings -; Off => Returns values as YYYY-MM-DD hh:mm:ss -;mssql.datetimeconvert = On - -; Use NT authentication when connecting to the server -mssql.secure_connection = Off - -; Specify max number of processes. -1 = library default -; msdlib defaults to 25 -; FreeTDS defaults to 4096 -;mssql.max_procs = -1 - -; Specify client character set. -; If empty or not set the client charset from freetds.conf is used -; This is only used when compiled with FreeTDS -;mssql.charset = "ISO-8859-1" - -[Assertion] -; Assert(expr); active by default. -; http://php.net/assert.active -;assert.active = On - -; Issue a PHP warning for each failed assertion. -; http://php.net/assert.warning -;assert.warning = On - -; Don't bail out by default. -; http://php.net/assert.bail -;assert.bail = Off - -; User-function to be called if an assertion fails. -; http://php.net/assert.callback -;assert.callback = 0 - -; Eval the expression with current error_reporting(). Set to true if you want -; error_reporting(0) around the eval(). -; http://php.net/assert.quiet-eval -;assert.quiet_eval = 0 - -[COM] -; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs -; http://php.net/com.typelib-file -;com.typelib_file = - -; allow Distributed-COM calls -; http://php.net/com.allow-dcom -;com.allow_dcom = true - -; autoregister constants of a components typlib on com_load() -; http://php.net/com.autoregister-typelib -;com.autoregister_typelib = true - -; register constants casesensitive -; http://php.net/com.autoregister-casesensitive -;com.autoregister_casesensitive = false - -; show warnings on duplicate constant registrations -; http://php.net/com.autoregister-verbose -;com.autoregister_verbose = true - -; The default character set code-page to use when passing strings to and from COM objects. -; Default: system ANSI code page -;com.code_page= - -[mbstring] -; language for internal character representation. -; http://php.net/mbstring.language -;mbstring.language = Japanese - -; internal/script encoding. -; Some encoding cannot work as internal encoding. -; (e.g. SJIS, BIG5, ISO-2022-*) -; http://php.net/mbstring.internal-encoding -;mbstring.internal_encoding = EUC-JP - -; http input encoding. -; http://php.net/mbstring.http-input -;mbstring.http_input = auto - -; http output encoding. mb_output_handler must be -; registered as output buffer to function -; http://php.net/mbstring.http-output -;mbstring.http_output = SJIS - -; enable automatic encoding translation according to -; mbstring.internal_encoding setting. Input chars are -; converted to internal encoding by setting this to On. -; Note: Do _not_ use automatic encoding translation for -; portable libs/applications. -; http://php.net/mbstring.encoding-translation -;mbstring.encoding_translation = Off - -; automatic encoding detection order. -; auto means -; http://php.net/mbstring.detect-order -;mbstring.detect_order = auto - -; substitute_character used when character cannot be converted -; one from another -; http://php.net/mbstring.substitute-character -;mbstring.substitute_character = none; - -; overload(replace) single byte functions by mbstring functions. -; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), -; etc. Possible values are 0,1,2,4 or combination of them. -; For example, 7 for overload everything. -; 0: No overload -; 1: Overload mail() function -; 2: Overload str*() functions -; 4: Overload ereg*() functions -; http://php.net/mbstring.func-overload -;mbstring.func_overload = 0 - -; enable strict encoding detection. -;mbstring.strict_detection = Off - -; This directive specifies the regex pattern of content types for which mb_output_handler() -; is activated. -; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) -;mbstring.http_output_conv_mimetype= - -; Allows to set script encoding. Only affects if PHP is compiled with --enable-zend-multibyte -; Default: "" -;mbstring.script_encoding= - -[gd] -; Tell the jpeg decode to ignore warnings and try to create -; a gd image. The warning will then be displayed as notices -; disabled by default -; http://php.net/gd.jpeg-ignore-warning -;gd.jpeg_ignore_warning = 0 - -[exif] -; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. -; With mbstring support this will automatically be converted into the encoding -; given by corresponding encode setting. When empty mbstring.internal_encoding -; is used. For the decode settings you can distinguish between motorola and -; intel byte order. A decode setting cannot be empty. -; http://php.net/exif.encode-unicode -;exif.encode_unicode = ISO-8859-15 - -; http://php.net/exif.decode-unicode-motorola -;exif.decode_unicode_motorola = UCS-2BE - -; http://php.net/exif.decode-unicode-intel -;exif.decode_unicode_intel = UCS-2LE - -; http://php.net/exif.encode-jis -;exif.encode_jis = - -; http://php.net/exif.decode-jis-motorola -;exif.decode_jis_motorola = JIS - -; http://php.net/exif.decode-jis-intel -;exif.decode_jis_intel = JIS - -[Tidy] -; The path to a default tidy configuration file to use when using tidy -; http://php.net/tidy.default-config -;tidy.default_config = /usr/local/lib/php/default.tcfg - -; Should tidy clean and repair output automatically? -; WARNING: Do not use this option if you are generating non-html content -; such as dynamic images -; http://php.net/tidy.clean-output -tidy.clean_output = Off - -[soap] -; Enables or disables WSDL caching feature. -; http://php.net/soap.wsdl-cache-enabled -soap.wsdl_cache_enabled=1 - -; Sets the directory name where SOAP extension will put cache files. -; http://php.net/soap.wsdl-cache-dir -soap.wsdl_cache_dir="/tmp" - -; (time to live) Sets the number of second while cached file will be used -; instead of original one. -; http://php.net/soap.wsdl-cache-ttl -soap.wsdl_cache_ttl=86400 - -; Sets the size of the cache limit. (Max. number of WSDL files to cache) -soap.wsdl_cache_limit = 5 - -[sysvshm] -; A default size of the shared memory segment -;sysvshm.init_mem = 10000 - -[ldap] -; Sets the maximum number of open links or -1 for unlimited. -ldap.max_links = -1 - -[mcrypt] -; For more information about mcrypt settings see http://php.net/mcrypt-module-open - -; Directory where to load mcrypt algorithms -; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) -;mcrypt.algorithms_dir= - -; Directory where to load mcrypt modes -; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) -;mcrypt.modes_dir= - -[dba] -;dba.default_handler= - -[xsl] -; Write operations from within XSLT are disabled by default. -; XSL_SECPREF_CREATE_DIRECTORY | XSL_SECPREF_WRITE_NETWORK | XSL_SECPREF_WRITE_FILE = 44 -; Set it to 0 to allow all operations -;xsl.security_prefs = 44 - -; Local Variables: -; tab-width: 4 -; End: -[PHP_BZ2] -extension=php_bz2.dll -[PHP_CURL] -extension=php_curl.dll -[PHP_GD2] -extension=php_gd2.dll -[PHP_GETTEXT] -extension=php_gettext.dll -[PHP_GMP] -extension=php_gmp.dll -[PHP_IMAP] -extension=php_imap.dll -[PHP_MBSTRING] -extension=php_mbstring.dll -[PHP_MYSQL] -extension=php_mysql.dll -[PHP_MYSQLI] -extension=php_mysqli.dll -[PHP_OPENSSL] -extension=php_openssl.dll -[PHP_PDO_MYSQL] -extension=php_pdo_mysql.dll -[PHP_PDO_ODBC] -extension=php_pdo_odbc.dll -[PHP_PDO_SQLITE] -extension=php_pdo_sqlite.dll -[PHP_PGSQL] -extension=php_pgsql.dll -[PHP_SOAP] -extension=php_soap.dll -[PHP_SOCKETS] -extension=php_sockets.dll -[PHP_SQLITE3] -extension=php_sqlite3.dll -[PHP_TIDY] -extension=php_tidy.dll -[PHP_XMLRPC] -extension=php_xmlrpc.dll -[PHP_EXIF] -extension=php_exif.dll - - -include_path=".;<%= node['php']['conf_dir'].gsub('/', '\\') %>" - -<% @directives.each do |directive, value| -%> -<%= "#{directive}=#{value}" %> -<% end -%> diff --git a/cookbooks/postfix/CHANGELOG.md b/cookbooks/postfix/CHANGELOG.md index a827d23..415b74c 100644 --- a/cookbooks/postfix/CHANGELOG.md +++ b/cookbooks/postfix/CHANGELOG.md @@ -2,6 +2,10 @@ This file is used to list changes made in each version of the postfix cookbook. +## 5.0.2 (2017-05-17) + +- Fix use_relay_restrictions_maps attribute misspelling in attributes file + ## 5.0.1 (2017-03-03) - Fix documentation error on inet-interfaces diff --git a/cookbooks/postfix/attributes/default.rb b/cookbooks/postfix/attributes/default.rb index a261125..d467072 100644 --- a/cookbooks/postfix/attributes/default.rb +++ b/cookbooks/postfix/attributes/default.rb @@ -1,5 +1,5 @@ # Author:: Joshua Timberman -# Copyright:: 2009-2016, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -395,6 +395,6 @@ default['postfix']['aliases'] = case node['platform'] {} end -if node['postfix']['use_relay_restirictions_maps'] +if node['postfix']['use_relay_restrictions_maps'] default['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" end diff --git a/cookbooks/postfix/metadata.json b/cookbooks/postfix/metadata.json index 2b162d5..e535f33 100644 --- a/cookbooks/postfix/metadata.json +++ b/cookbooks/postfix/metadata.json @@ -1 +1 @@ -{"name":"postfix","version":"5.0.1","description":"Installs and configures postfix for client or outbound relayhost, or to do SASL auth","long_description":"# postfix Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/postfix.svg?branch=master)](https://travis-ci.org/chef-cookbooks/postfix) [![Cookbook Version](https://img.shields.io/cookbook/v/postfix.svg)](https://supermarket.chef.io/cookbooks/postfix)\n\nInstalls and configures postfix for client or outbound relayhost, or to do SASL authentication.\n\nOn RHEL-family systems, sendmail will be replaced with postfix.\n\n## Requirements\n\n### Platforms\n\n- Ubuntu 12.04+\n- Debian 7.0+\n- RHEL/CentOS/Scientific 5.7+, 6.2+\n- Amazon Linux (as of AMIs created after 4/9/2012)\n\nMay work on other platforms with or without modification.\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- none\n\n## Attributes\n\nSee `attributes/default.rb` for default values.\n\n### Generic cookbook attributes\n\n- `node['postfix']['mail_type']` - Sets the kind of mail configuration. `master` will set up a server (relayhost).\n- `node['postfix']['relayhost_role']` - name of a role used for search in the client recipe.\n- `node['postfix']['multi_environment_relay']` - set to true if nodes should not constrain search for the relayhost in their own environment.\n- `node['postfix']['use_procmail']` - set to true if nodes should use procmail as the delivery agent.\n- `node['postfix']['use_alias_maps']` - set to true if you want the cookbook to use/configure alias maps\n- `node['postfix']['use_transport_maps']` - set to true if you want the cookbook to use/configure transport maps\n- `node['postfix']['use_access_maps']` - set to true if you want the cookbook to use/configure access maps\n- `node['postfix']['use_virtual_aliases']` - set to true if you want the cookbook to use/configure virtual alias maps\n- `node['postfix']['use_relay_restrictions_maps']` - set to true if you want the cookbook to use/configure a list of domains to which postfix will allow relay\n- `node['postfix']['aliases']` - hash of aliases to create with `recipe[postfix::aliases]`, see below under **Recipes** for more information.\n- `node['postfix']['transports']` - hash of transports to create with `recipe[postfix::transports]`, see below under **Recipes** for more information.\n- `node['postfix']['access']` - hash of access to create with `recipe[postfix::access]`, see below under **Recipes** for more information.\n- `node['postfix']['virtual_aliases']` - hash of virtual_aliases to create with `recipe[postfix::virtual_aliases]`, see below under __Recipes__ for more information.\n- `node['postfix']['main_template_source']` - Cookbook source for main.cf template. Default 'postfix'\n- `node['postfix']['master_template_source']` - Cookbook source for master.cf template. Default 'postfix'\n\n### main.cf and sasl_passwd template attributes\n\nThe main.cf template has been simplified to include any attributes in the `node['postfix']['main']` data structure. The following attributes are still included with this cookbook to maintain some semblance of backwards compatibility.\n\nThis change in namespace to `node['postfix']['main']` should allow for greater flexibility, given the large number of configuration variables for the postfix daemon. All of these cookbook attributes correspond to the option of the same name in `/etc/postfix/main.cf`.\n\n- `node['postfix']['main']['biff']` - (yes/no); default no\n- `node['postfix']['main']['append_dot_mydomain']` - (yes/no); default no\n- `node['postfix']['main']['myhostname']` - defaults to fqdn from Ohai\n- `node['postfix']['main']['mydomain']` - defaults to domain from Ohai\n- `node['postfix']['main']['myorigin']` - defaults to $myhostname\n- `node['postfix']['main']['mynetworks']` - default is nil, which forces Postfix to default to loopback addresses.\n- `node['postfix']['main']['inet_interfaces']` - set to `loopback-only`, or `all` for server recipe\n- `node['postfix']['main']['alias_maps']` - set to `hash:/etc/aliases`\n- `node['postfix']['main']['mailbox_size_limit']` - set to `0` (disabled)\n- `node['postfix']['main']['mydestination']` - default fqdn, hostname, localhost.localdomain, localhost\n- `node['postfix']['main']['smtpd_use_tls']` - (yes/no); default yes. See conditional cert/key attributes.\n- `node['postfix']['main']['smtpd_tls_cert_file']` - conditional attribute, set to full path of server's x509 certificate.\n- `node['postfix']['main']['smtpd_tls_key_file']` - conditional attribute, set to full path of server's private key\n- `node['postfix']['main']['smtpd_tls_CAfile']` - set to platform specific CA bundle\n- `node['postfix']['main']['smtpd_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache`\n- `node['postfix']['main']['smtp_use_tls']` - (yes/no); default yes. See following conditional attributes.\n- `node['postfix']['main']['smtp_tls_CAfile']` - set to platform specific CA bundle\n- `node['postfix']['main']['smtp_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache`\n- `node['postfix']['main']['smtp_sasl_auth_enable']` - (yes/no); default no. If enabled, see following conditional attributes.\n- `node['postfix']['main']['smtp_sasl_password_maps']` - Set to `hash:/etc/postfix/sasl_passwd` template file\n- `node['postfix']['main']['smtp_sasl_security_options']` - Set to noanonymous\n- `node['postfix']['main']['relayhost']` - Set to empty string\n- `node['postfix']['sasl']['smtp_sasl_user_name']` - SASL user to authenticate as. Default empty\n- `node['postfix']['sasl']['smtp_sasl_passwd']` - SASL password to use. Default empty.\n- `node['postfix']['sender_canonical_map_entries']` - (hash with key value pairs); default not configured. Setup generic canonical maps. See `man 5 canonical`. If has at least one value, then will be enabled in config.\n- `node['postfix']['smtp_generic_map_entries']` - (hash with key value pairs); default not configured. Setup generic postfix maps. See `man 5 generic`. If has at least one value, then will be enabled in config.\n\nExample of json role config, for setup *_map_entries:\n\n`postfix : {`\n\n`...`\n\n`\"smtp_generic_map_entries\" : { \"root@youinternaldomain.local\" : \"admin@example.com\", \"admin@youinternaldomain.local\" : \"admin@example.com\" }`\n\n`}`\n\n### master.cf template attributes\n\nThe master.cf template has been changed to allow full customization of the file content. For purpose of backwards compatibility default attributes generate the same master.cf. But via `node['postfix']['master']` data structure in your role for instance it can be completelly rewritten.\n\nExamples of json role config, for customize master.cf:\n\n`postfix : {`\n\n`...`\n\nturn some services off or on:\n\n```json\n \"master\" : {\n \"smtps\": {\n \"active\": true\n },\n \"old-cyrus\": {\n \"active\": false\n },\n \"cyrus\": {\n \"active\": false\n },\n \"uucp\": {\n \"active\": false\n },\n \"ifmail\": {\n \"active\": false\n },\n```\n\n`...` define you own service:\n\n```json\n \"spamfilter\": {\n \"comment\": \"My own spamfilter\",\n \"active\": true,\n \"order\": 590,\n \"type\": \"unix\",\n \"unpriv\": false,\n \"chroot\": false,\n \"command\": \"pipe\",\n \"args\": [\"flags=Rq user=spamd argv=/usr/bin/spamfilter.sh -oi -f ${sender} ${recipient}\"]\n }\n```\n\n`...`\n\n`}` `}`\n\nThe possible service hash fields and their meanings: hash key - have to be unique, unless you wish to override default definition.\n\nField | Mandatory | Description\n------- | --------- | --------------------------------------------------------------------\nactive | Yes | Boolean. Defines whether or not the service needs to be in master.cf\ncomment | No | String. If you would like to add a comment line before service line\norder | Yes | Integer. Number to define the order of lines in the file\ntype | Yes | String. Type of the service (inet, unix, fifo)\nprivate | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nunpriv | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nchroot | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nwakeup | No | String. If present value placed in file, otherwise replaced by `-`\nmaxproc | No | String. If present value placed in file, otherwise replaced by `-`\ncommand | Yes | String. The command to be executed.\nargs | Yes | Array of Strings. Arguments passed to command.\n\nFor more information about meaning of the fields consult `master (5)` manual: \n\n## Recipes\n\n### default\n\nInstalls the postfix package and manages the service and the main configuration files (`/etc/postfix/main.cf` and `/etc/postfix/master.cf`). See **Usage** and **Examples** to see how to affect behavior of this recipe through configuration. Depending on the `node['postfix']['use_alias_maps']`, `node['postfix']['use_transport_maps']`, `node['postfix']['use_access_maps']` and `node['postfix']['use_virtual_aliases']` attributes the default recipe can call additional recipes to manage additional postfix configuration files\n\nFor a more dynamic approach to discovery for the relayhost, see the `client` and `server` recipes below.\n\n### client\n\nUse this recipe to have nodes automatically search for the mail relay based which node has the `node['postfix']['relayhost_role']` role. Sets the `node['postfix']['main']['relayhost']` attribute to the first result from the search.\n\nIncludes the default recipe to install, configure and start postfix.\n\nDoes not work with `chef-solo`.\n\n### sasl_auth\n\nSets up the system to authenticate with a remote mail relay using SASL authentication.\n\n### server\n\nTo use Chef Server search to automatically detect a node that is the relayhost, use this recipe in a role that will be relayhost. By default, the role should be \"relayhost\" but you can change the attribute `node['postfix']['relayhost_role']` to modify this.\n\n**Note** This recipe will set the `node['postfix']['mail_type']` to \"master\" with an override attribute.\n\n### maps\n\nGeneral recipe to manage any number of any type postfix lookup tables. You can replace with it recipes like `transport` or `virtual_aliases`, but what is more important - you can create any kinds of maps, which has no own recipe, including database lookup maps configuration. `maps` is a hash keys of which is a lookup table type and value is another hash with filenames as the keys and hash with file content as the value. File content is an any number of key/value pairs which meaning depends on lookup table type. Examlle:\n\n```json\n \"override_attributes\": {\n \"postfix\": {\n \"maps\": {\n \"hash\": {\n \"/etc/postfix/vmailbox\": {\n \"john@example.com\": \"ok\",\n \"john@example.net\": \"ok\",\n },\n \"/etc/postfix/virtual\": {\n \"postmaster@example.com\": \"john@example.com\",\n \"postmaster@example.net\": \"john@example.net\",\n \"root@mail.example.net\": \"john@example.net\"\n },\n \"/etc/postfix/envelope_senders\": {\n \"@example.com\": \"john@example.com\",\n \"@example.net\": \"john@example.net\"\n },\n \"/etc/postfix/relay_recipients\": {\n \"john@example.net\": \"ok\",\n \"john@example.com\": \"ok\",\n \"admin@example.com\": \"ok\",\n }\n },\n \"pgsql\": {\n \"/etc/postfix/pgtest\": {\n \"hosts\": \"db.local:2345\",\n \"user\": \"postfix\",\n \"password\": \"test\",\n \"dbname\": \"postdb\",\n \"query\": \"SELECT replacement FROM aliases WHERE mailbox = '%s'\"\n }\n }\n }\n }\n```\n\nTo use these files in your configuration reference them in `node['postfix']['main']`, for instance:\n\n```json\n \"postfix\": {\n \"main\": {\n \"smtpd_sender_login_maps\": \"hash:/etc/postfix/envelope_senders\",\n \"relay_recipient_maps\": \"hash:/etc/postfix/relay_recipients\",\n \"virtual_mailbox_maps\": \"hash:/etc/postfix/vmailbox\",\n \"virtual_alias_maps\": \"hash:/etc/postfix/virtual\",\n }\n }\n```\n\n### aliases\n\nManage `/etc/aliases` with this recipe. Currently only Ubuntu 10.04 platform has a template for the aliases file. Add your aliases template to the `templates/default` or to the appropriate platform+version directory per the File Specificity rules for templates. Then specify a hash of aliases for the `node['postfix']['aliases']` attribute.\n\nArrays are supported as alias values, since postfix supports comma separated values per alias, simply specify your alias as an array to use this handy feature.\n\n### aliases\n\nManage `/etc/aliases` with this recipe.\n\n### transports\n\nManage `/etc/postfix/transport` with this recipe.\n\n### access\n\nManage `/etc/postfix/access` with this recipe.\n\n### virtual_aliases\n\nManage `/etc/postfix/virtual` with this recipe.\n\n### relay_restrictions\n\nManage `/etc/postfix/relay_restriction` with this recipe The postfix option smtpd_relay_restrictions in main.cf will point to this hash map db.\n\n\n\n## Usage\n\nOn systems that should simply send mail directly to a relay, or out to the internet, use `recipe[postfix]` and modify the `node['postfix']['main']['relayhost']` attribute via a role.\n\nOn systems that should be the MX for a domain, set the attributes accordingly and make sure the `node['postfix']['mail_type']` attribute is `master`. See **Examples** for information on how to use `recipe[postfix::server]` to do this automatically.\n\nIf you need to use SASL authentication to send mail through your ISP (such as on a home network), use `postfix::sasl_auth` and set the appropriate attributes.\n\nFor each of these implementations, see **Examples** for role usage.\n\n### Examples\n\nThe example roles below only have the relevant postfix usage. You may have other contents depending on what you're configuring on your systems.\n\nThe `base` role is applied to all nodes in the environment.\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\",\n \"relayhost\" => \"[smtp.example.com]\",\n \"smtp_use_tls\" => \"no\"\n }\n }\n)\n```\n\nThe `relayhost` role is applied to the nodes that are relayhosts. Often this is 2 systems using a CNAME of `smtp.example.com`.\n\n```ruby\nname \"relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"master\",\n \"main\" => {\n \"mynetworks\" => [ \"10.3.3.0/24\", \"127.0.0.0/8\" ],\n \"inet_interfaces\" => \"all\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n)\n```\n\nThe `sasl_relayhost` role is applied to the nodes that are relayhosts and require authenticating with SASL. For example this might be on a household network with an ISP that otherwise blocks direct internet access to SMTP.\n\n```ruby\nname \"sasl_relayhost\"\nrun_list(\"recipe[postfix], recipe[postfix::sasl_auth]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"master\",\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\",\n \"relayhost\" => \"[smtp.comcast.net]:587\",\n \"smtp_sasl_auth_enable\" => \"yes\"\n },\n \"sasl\" => {\n \"smtp_sasl_passwd\" => \"your_password\",\n \"smtp_sasl_user_name\" => \"your_username\"\n }\n }\n)\n```\n\nFor an example of using encrypted data bags to encrypt the SASL password, see the following blog post:\n\n- \n\n#### Examples using the client & server recipes\n\nIf you'd like to use the more dynamic search based approach for discovery, use the server and client recipes. First, create a relayhost role.\n\n```ruby\nname \"relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nThen, add the `postfix::client` recipe to the run list of your `base` role or equivalent role for postfix clients.\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix::client]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nIf you wish to use a different role name for the relayhost, then also set the attribute in the `base` role. For example, `postfix_master` as the role name:\n\n```ruby\nname \"postfix_master\"\ndescription \"a role for postfix master that isn't relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nThe base role would look something like this:\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix::client]\")\noverride_attributes(\n \"postfix\" => {\n \"relayhost_role\" => \"postfix_master\",\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nTo use relay restrictions override the relay restrictions attribute in this format:\n\n```ruby\noverride_attributes(\n \"postfix\" => {\n \"use_relay_restrictions_maps\" => true,\n \"relay_restrictions\" => {\n \"chef.io\" => \"OK\",\n \".chef.io\" => \"OK\",\n \"example.com\" => \"OK\"\n }\n }\n)\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2009-2016, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","amazon":">= 0.0.0","oracle":">= 0.0.0","scientific":">= 0.0.0","smartos":">= 0.0.0","fedora":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"postfix":"Installs and configures postfix","postfix::sasl_auth":"Set up postfix to auth to a server with sasl","postfix::aliases":"Manages /etc/aliases","postfix::transports":"Manages /etc/postfix/transport","postfix::access":"Manages /etc/postfix/access","postfix::virtual_aliases":"Manages /etc/postfix/virtual","postfix::client":"Searches for the relayhost based on an attribute","postfix::server":"Sets the mail_type attribute to master","postfix::maps":"Manages any number of any type postfix lookup tables"}} \ No newline at end of file +{"name":"postfix","version":"5.0.2","description":"Installs and configures postfix for client or outbound relayhost, or to do SASL auth","long_description":"# postfix Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/postfix.svg?branch=master)](https://travis-ci.org/chef-cookbooks/postfix) [![Cookbook Version](https://img.shields.io/cookbook/v/postfix.svg)](https://supermarket.chef.io/cookbooks/postfix)\n\nInstalls and configures postfix for client or outbound relayhost, or to do SASL authentication.\n\nOn RHEL-family systems, sendmail will be replaced with postfix.\n\n## Requirements\n\n### Platforms\n\n- Ubuntu 12.04+\n- Debian 7.0+\n- RHEL/CentOS/Scientific 5.7+, 6.2+\n- Amazon Linux (as of AMIs created after 4/9/2012)\n\nMay work on other platforms with or without modification.\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- none\n\n## Attributes\n\nSee `attributes/default.rb` for default values.\n\n### Generic cookbook attributes\n\n- `node['postfix']['mail_type']` - Sets the kind of mail configuration. `master` will set up a server (relayhost).\n- `node['postfix']['relayhost_role']` - name of a role used for search in the client recipe.\n- `node['postfix']['multi_environment_relay']` - set to true if nodes should not constrain search for the relayhost in their own environment.\n- `node['postfix']['use_procmail']` - set to true if nodes should use procmail as the delivery agent.\n- `node['postfix']['use_alias_maps']` - set to true if you want the cookbook to use/configure alias maps\n- `node['postfix']['use_transport_maps']` - set to true if you want the cookbook to use/configure transport maps\n- `node['postfix']['use_access_maps']` - set to true if you want the cookbook to use/configure access maps\n- `node['postfix']['use_virtual_aliases']` - set to true if you want the cookbook to use/configure virtual alias maps\n- `node['postfix']['use_relay_restrictions_maps']` - set to true if you want the cookbook to use/configure a list of domains to which postfix will allow relay\n- `node['postfix']['aliases']` - hash of aliases to create with `recipe[postfix::aliases]`, see below under **Recipes** for more information.\n- `node['postfix']['transports']` - hash of transports to create with `recipe[postfix::transports]`, see below under **Recipes** for more information.\n- `node['postfix']['access']` - hash of access to create with `recipe[postfix::access]`, see below under **Recipes** for more information.\n- `node['postfix']['virtual_aliases']` - hash of virtual_aliases to create with `recipe[postfix::virtual_aliases]`, see below under __Recipes__ for more information.\n- `node['postfix']['main_template_source']` - Cookbook source for main.cf template. Default 'postfix'\n- `node['postfix']['master_template_source']` - Cookbook source for master.cf template. Default 'postfix'\n\n### main.cf and sasl_passwd template attributes\n\nThe main.cf template has been simplified to include any attributes in the `node['postfix']['main']` data structure. The following attributes are still included with this cookbook to maintain some semblance of backwards compatibility.\n\nThis change in namespace to `node['postfix']['main']` should allow for greater flexibility, given the large number of configuration variables for the postfix daemon. All of these cookbook attributes correspond to the option of the same name in `/etc/postfix/main.cf`.\n\n- `node['postfix']['main']['biff']` - (yes/no); default no\n- `node['postfix']['main']['append_dot_mydomain']` - (yes/no); default no\n- `node['postfix']['main']['myhostname']` - defaults to fqdn from Ohai\n- `node['postfix']['main']['mydomain']` - defaults to domain from Ohai\n- `node['postfix']['main']['myorigin']` - defaults to $myhostname\n- `node['postfix']['main']['mynetworks']` - default is nil, which forces Postfix to default to loopback addresses.\n- `node['postfix']['main']['inet_interfaces']` - set to `loopback-only`, or `all` for server recipe\n- `node['postfix']['main']['alias_maps']` - set to `hash:/etc/aliases`\n- `node['postfix']['main']['mailbox_size_limit']` - set to `0` (disabled)\n- `node['postfix']['main']['mydestination']` - default fqdn, hostname, localhost.localdomain, localhost\n- `node['postfix']['main']['smtpd_use_tls']` - (yes/no); default yes. See conditional cert/key attributes.\n- `node['postfix']['main']['smtpd_tls_cert_file']` - conditional attribute, set to full path of server's x509 certificate.\n- `node['postfix']['main']['smtpd_tls_key_file']` - conditional attribute, set to full path of server's private key\n- `node['postfix']['main']['smtpd_tls_CAfile']` - set to platform specific CA bundle\n- `node['postfix']['main']['smtpd_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache`\n- `node['postfix']['main']['smtp_use_tls']` - (yes/no); default yes. See following conditional attributes.\n- `node['postfix']['main']['smtp_tls_CAfile']` - set to platform specific CA bundle\n- `node['postfix']['main']['smtp_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache`\n- `node['postfix']['main']['smtp_sasl_auth_enable']` - (yes/no); default no. If enabled, see following conditional attributes.\n- `node['postfix']['main']['smtp_sasl_password_maps']` - Set to `hash:/etc/postfix/sasl_passwd` template file\n- `node['postfix']['main']['smtp_sasl_security_options']` - Set to noanonymous\n- `node['postfix']['main']['relayhost']` - Set to empty string\n- `node['postfix']['sasl']['smtp_sasl_user_name']` - SASL user to authenticate as. Default empty\n- `node['postfix']['sasl']['smtp_sasl_passwd']` - SASL password to use. Default empty.\n- `node['postfix']['sender_canonical_map_entries']` - (hash with key value pairs); default not configured. Setup generic canonical maps. See `man 5 canonical`. If has at least one value, then will be enabled in config.\n- `node['postfix']['smtp_generic_map_entries']` - (hash with key value pairs); default not configured. Setup generic postfix maps. See `man 5 generic`. If has at least one value, then will be enabled in config.\n\nExample of json role config, for setup *_map_entries:\n\n`postfix : {`\n\n`...`\n\n`\"smtp_generic_map_entries\" : { \"root@youinternaldomain.local\" : \"admin@example.com\", \"admin@youinternaldomain.local\" : \"admin@example.com\" }`\n\n`}`\n\n### master.cf template attributes\n\nThe master.cf template has been changed to allow full customization of the file content. For purpose of backwards compatibility default attributes generate the same master.cf. But via `node['postfix']['master']` data structure in your role for instance it can be completelly rewritten.\n\nExamples of json role config, for customize master.cf:\n\n`postfix : {`\n\n`...`\n\nturn some services off or on:\n\n```json\n \"master\" : {\n \"smtps\": {\n \"active\": true\n },\n \"old-cyrus\": {\n \"active\": false\n },\n \"cyrus\": {\n \"active\": false\n },\n \"uucp\": {\n \"active\": false\n },\n \"ifmail\": {\n \"active\": false\n },\n```\n\n`...` define you own service:\n\n```json\n \"spamfilter\": {\n \"comment\": \"My own spamfilter\",\n \"active\": true,\n \"order\": 590,\n \"type\": \"unix\",\n \"unpriv\": false,\n \"chroot\": false,\n \"command\": \"pipe\",\n \"args\": [\"flags=Rq user=spamd argv=/usr/bin/spamfilter.sh -oi -f ${sender} ${recipient}\"]\n }\n```\n\n`...`\n\n`}` `}`\n\nThe possible service hash fields and their meanings: hash key - have to be unique, unless you wish to override default definition.\n\nField | Mandatory | Description\n------- | --------- | --------------------------------------------------------------------\nactive | Yes | Boolean. Defines whether or not the service needs to be in master.cf\ncomment | No | String. If you would like to add a comment line before service line\norder | Yes | Integer. Number to define the order of lines in the file\ntype | Yes | String. Type of the service (inet, unix, fifo)\nprivate | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nunpriv | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nchroot | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nwakeup | No | String. If present value placed in file, otherwise replaced by `-`\nmaxproc | No | String. If present value placed in file, otherwise replaced by `-`\ncommand | Yes | String. The command to be executed.\nargs | Yes | Array of Strings. Arguments passed to command.\n\nFor more information about meaning of the fields consult `master (5)` manual: \n\n## Recipes\n\n### default\n\nInstalls the postfix package and manages the service and the main configuration files (`/etc/postfix/main.cf` and `/etc/postfix/master.cf`). See **Usage** and **Examples** to see how to affect behavior of this recipe through configuration. Depending on the `node['postfix']['use_alias_maps']`, `node['postfix']['use_transport_maps']`, `node['postfix']['use_access_maps']` and `node['postfix']['use_virtual_aliases']` attributes the default recipe can call additional recipes to manage additional postfix configuration files\n\nFor a more dynamic approach to discovery for the relayhost, see the `client` and `server` recipes below.\n\n### client\n\nUse this recipe to have nodes automatically search for the mail relay based which node has the `node['postfix']['relayhost_role']` role. Sets the `node['postfix']['main']['relayhost']` attribute to the first result from the search.\n\nIncludes the default recipe to install, configure and start postfix.\n\nDoes not work with `chef-solo`.\n\n### sasl_auth\n\nSets up the system to authenticate with a remote mail relay using SASL authentication.\n\n### server\n\nTo use Chef Server search to automatically detect a node that is the relayhost, use this recipe in a role that will be relayhost. By default, the role should be \"relayhost\" but you can change the attribute `node['postfix']['relayhost_role']` to modify this.\n\n**Note** This recipe will set the `node['postfix']['mail_type']` to \"master\" with an override attribute.\n\n### maps\n\nGeneral recipe to manage any number of any type postfix lookup tables. You can replace with it recipes like `transport` or `virtual_aliases`, but what is more important - you can create any kinds of maps, which has no own recipe, including database lookup maps configuration. `maps` is a hash keys of which is a lookup table type and value is another hash with filenames as the keys and hash with file content as the value. File content is an any number of key/value pairs which meaning depends on lookup table type. Examlle:\n\n```json\n \"override_attributes\": {\n \"postfix\": {\n \"maps\": {\n \"hash\": {\n \"/etc/postfix/vmailbox\": {\n \"john@example.com\": \"ok\",\n \"john@example.net\": \"ok\",\n },\n \"/etc/postfix/virtual\": {\n \"postmaster@example.com\": \"john@example.com\",\n \"postmaster@example.net\": \"john@example.net\",\n \"root@mail.example.net\": \"john@example.net\"\n },\n \"/etc/postfix/envelope_senders\": {\n \"@example.com\": \"john@example.com\",\n \"@example.net\": \"john@example.net\"\n },\n \"/etc/postfix/relay_recipients\": {\n \"john@example.net\": \"ok\",\n \"john@example.com\": \"ok\",\n \"admin@example.com\": \"ok\",\n }\n },\n \"pgsql\": {\n \"/etc/postfix/pgtest\": {\n \"hosts\": \"db.local:2345\",\n \"user\": \"postfix\",\n \"password\": \"test\",\n \"dbname\": \"postdb\",\n \"query\": \"SELECT replacement FROM aliases WHERE mailbox = '%s'\"\n }\n }\n }\n }\n```\n\nTo use these files in your configuration reference them in `node['postfix']['main']`, for instance:\n\n```json\n \"postfix\": {\n \"main\": {\n \"smtpd_sender_login_maps\": \"hash:/etc/postfix/envelope_senders\",\n \"relay_recipient_maps\": \"hash:/etc/postfix/relay_recipients\",\n \"virtual_mailbox_maps\": \"hash:/etc/postfix/vmailbox\",\n \"virtual_alias_maps\": \"hash:/etc/postfix/virtual\",\n }\n }\n```\n\n### aliases\n\nManage `/etc/aliases` with this recipe. Currently only Ubuntu 10.04 platform has a template for the aliases file. Add your aliases template to the `templates/default` or to the appropriate platform+version directory per the File Specificity rules for templates. Then specify a hash of aliases for the `node['postfix']['aliases']` attribute.\n\nArrays are supported as alias values, since postfix supports comma separated values per alias, simply specify your alias as an array to use this handy feature.\n\n### aliases\n\nManage `/etc/aliases` with this recipe.\n\n### transports\n\nManage `/etc/postfix/transport` with this recipe.\n\n### access\n\nManage `/etc/postfix/access` with this recipe.\n\n### virtual_aliases\n\nManage `/etc/postfix/virtual` with this recipe.\n\n### relay_restrictions\n\nManage `/etc/postfix/relay_restriction` with this recipe The postfix option smtpd_relay_restrictions in main.cf will point to this hash map db.\n\n\n\n## Usage\n\nOn systems that should simply send mail directly to a relay, or out to the internet, use `recipe[postfix]` and modify the `node['postfix']['main']['relayhost']` attribute via a role.\n\nOn systems that should be the MX for a domain, set the attributes accordingly and make sure the `node['postfix']['mail_type']` attribute is `master`. See **Examples** for information on how to use `recipe[postfix::server]` to do this automatically.\n\nIf you need to use SASL authentication to send mail through your ISP (such as on a home network), use `postfix::sasl_auth` and set the appropriate attributes.\n\nFor each of these implementations, see **Examples** for role usage.\n\n### Examples\n\nThe example roles below only have the relevant postfix usage. You may have other contents depending on what you're configuring on your systems.\n\nThe `base` role is applied to all nodes in the environment.\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\",\n \"relayhost\" => \"[smtp.example.com]\",\n \"smtp_use_tls\" => \"no\"\n }\n }\n)\n```\n\nThe `relayhost` role is applied to the nodes that are relayhosts. Often this is 2 systems using a CNAME of `smtp.example.com`.\n\n```ruby\nname \"relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"master\",\n \"main\" => {\n \"mynetworks\" => [ \"10.3.3.0/24\", \"127.0.0.0/8\" ],\n \"inet_interfaces\" => \"all\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n)\n```\n\nThe `sasl_relayhost` role is applied to the nodes that are relayhosts and require authenticating with SASL. For example this might be on a household network with an ISP that otherwise blocks direct internet access to SMTP.\n\n```ruby\nname \"sasl_relayhost\"\nrun_list(\"recipe[postfix], recipe[postfix::sasl_auth]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"master\",\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\",\n \"relayhost\" => \"[smtp.comcast.net]:587\",\n \"smtp_sasl_auth_enable\" => \"yes\"\n },\n \"sasl\" => {\n \"smtp_sasl_passwd\" => \"your_password\",\n \"smtp_sasl_user_name\" => \"your_username\"\n }\n }\n)\n```\n\nFor an example of using encrypted data bags to encrypt the SASL password, see the following blog post:\n\n- \n\n#### Examples using the client & server recipes\n\nIf you'd like to use the more dynamic search based approach for discovery, use the server and client recipes. First, create a relayhost role.\n\n```ruby\nname \"relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nThen, add the `postfix::client` recipe to the run list of your `base` role or equivalent role for postfix clients.\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix::client]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nIf you wish to use a different role name for the relayhost, then also set the attribute in the `base` role. For example, `postfix_master` as the role name:\n\n```ruby\nname \"postfix_master\"\ndescription \"a role for postfix master that isn't relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nThe base role would look something like this:\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix::client]\")\noverride_attributes(\n \"postfix\" => {\n \"relayhost_role\" => \"postfix_master\",\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nTo use relay restrictions override the relay restrictions attribute in this format:\n\n```ruby\noverride_attributes(\n \"postfix\" => {\n \"use_relay_restrictions_maps\" => true,\n \"relay_restrictions\" => {\n \"chef.io\" => \"OK\",\n \".chef.io\" => \"OK\",\n \"example.com\" => \"OK\"\n }\n }\n)\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2009-2016, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","amazon":">= 0.0.0","oracle":">= 0.0.0","scientific":">= 0.0.0","smartos":">= 0.0.0","fedora":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"postfix":"Installs and configures postfix","postfix::sasl_auth":"Set up postfix to auth to a server with sasl","postfix::aliases":"Manages /etc/aliases","postfix::transports":"Manages /etc/postfix/transport","postfix::access":"Manages /etc/postfix/access","postfix::virtual_aliases":"Manages /etc/postfix/virtual","postfix::client":"Searches for the relayhost based on an attribute","postfix::server":"Sets the mail_type attribute to master","postfix::maps":"Manages any number of any type postfix lookup tables"},"source_url":"https://github.com/chef-cookbooks/postfix","issues_url":"https://github.com/chef-cookbooks/postfix/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file diff --git a/cookbooks/postfix/recipes/_attributes.rb b/cookbooks/postfix/recipes/_attributes.rb index a570533..f3ffe6e 100644 --- a/cookbooks/postfix/recipes/_attributes.rb +++ b/cookbooks/postfix/recipes/_attributes.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -58,7 +58,7 @@ if node['postfix']['use_virtual_aliases_domains'] node.default_unless['postfix']['main']['virtual_alias_domains'] = ["#{node['postfix']['virtual_alias_domains_db_type']}:#{node['postfix']['virtual_alias_domains_db']}"] end -if node['postfix']['use_relay_restirictions_maps'] +if node['postfix']['use_relay_restrictions_maps'] default['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" end diff --git a/cookbooks/postfix/recipes/_common.rb b/cookbooks/postfix/recipes/_common.rb index fc0fcc0..17d5e0e 100644 --- a/cookbooks/postfix/recipes/_common.rb +++ b/cookbooks/postfix/recipes/_common.rb @@ -2,7 +2,7 @@ # Cookbook:: common # Recipe:: default # -# Copyright:: 2009-2016, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/access.rb b/cookbooks/postfix/recipes/access.rb index 34766f6..62e3025 100644 --- a/cookbooks/postfix/recipes/access.rb +++ b/cookbooks/postfix/recipes/access.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/aliases.rb b/cookbooks/postfix/recipes/aliases.rb index 45253f0..67d6db7 100644 --- a/cookbooks/postfix/recipes/aliases.rb +++ b/cookbooks/postfix/recipes/aliases.rb @@ -1,4 +1,4 @@ -# Copyright:: Copyright 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/client.rb b/cookbooks/postfix/recipes/client.rb index edb7283..2231ce2 100644 --- a/cookbooks/postfix/recipes/client.rb +++ b/cookbooks/postfix/recipes/client.rb @@ -2,7 +2,7 @@ # Cookbook:: postfix # Recipe:: client # -# Copyright:: 2009-2016, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/default.rb b/cookbooks/postfix/recipes/default.rb index 3fd8a04..07026e4 100644 --- a/cookbooks/postfix/recipes/default.rb +++ b/cookbooks/postfix/recipes/default.rb @@ -2,7 +2,7 @@ # Cookbook:: postfix # Recipe:: default # -# Copyright:: 2009-2016, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/maps.rb b/cookbooks/postfix/recipes/maps.rb index 9aa06e8..9c47486 100644 --- a/cookbooks/postfix/recipes/maps.rb +++ b/cookbooks/postfix/recipes/maps.rb @@ -1,5 +1,5 @@ # encoding: utf-8 -# Copyright:: Copyright (c) 2012, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/relay_restrictions.rb b/cookbooks/postfix/recipes/relay_restrictions.rb index 8e458f9..c5548e4 100644 --- a/cookbooks/postfix/recipes/relay_restrictions.rb +++ b/cookbooks/postfix/recipes/relay_restrictions.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/sasl_auth.rb b/cookbooks/postfix/recipes/sasl_auth.rb index d8079ca..38f040e 100644 --- a/cookbooks/postfix/recipes/sasl_auth.rb +++ b/cookbooks/postfix/recipes/sasl_auth.rb @@ -3,7 +3,7 @@ # Cookbook:: postfix # Recipe:: sasl_auth # -# Copyright:: 2009-2016, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/server.rb b/cookbooks/postfix/recipes/server.rb index 4fd6e57..2166777 100644 --- a/cookbooks/postfix/recipes/server.rb +++ b/cookbooks/postfix/recipes/server.rb @@ -3,7 +3,7 @@ # Cookbook:: postfix # Recipe:: server # -# Copyright:: 2009-2016, Chef Software, Inc. +# Copyright:: 2009-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/transports.rb b/cookbooks/postfix/recipes/transports.rb index 40eea63..7386caa 100644 --- a/cookbooks/postfix/recipes/transports.rb +++ b/cookbooks/postfix/recipes/transports.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/virtual_aliases.rb b/cookbooks/postfix/recipes/virtual_aliases.rb index caedec5..f8e9eda 100644 --- a/cookbooks/postfix/recipes/virtual_aliases.rb +++ b/cookbooks/postfix/recipes/virtual_aliases.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/virtual_aliases_domains.rb b/cookbooks/postfix/recipes/virtual_aliases_domains.rb index b835c17..067b697 100644 --- a/cookbooks/postfix/recipes/virtual_aliases_domains.rb +++ b/cookbooks/postfix/recipes/virtual_aliases_domains.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2016, Chef Software, Inc. +# Copyright:: 2012-2017, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/rbac/README.md b/cookbooks/rbac/README.md deleted file mode 100644 index e7f3f74..0000000 --- a/cookbooks/rbac/README.md +++ /dev/null @@ -1,82 +0,0 @@ -Role based access control -========================= - -Solaris and Illumos provide sophisticated role-based access control for -delegating authorizations within the system. Using RBAC, users can be -given permissions to manage and update services without sudo. - -This cookbook provides chef with LWRPs to manage RBAC and grant permissions. - -At this time this cookbook ONLY manages SMF-related permissions (ie, ability -of non-priviliged users to start/stop SMF services), but in the future it may -be enhanced to support arbitrary Solaris permissions. - -## Installation - -In order to add the RBAC LWRPs to a chef run, add the following recipe -to the run_list: - - rbac::default - -This will do no work, but will load the providers. - -## LWRPs - -### rbac - -Defines a set of authorizations that can be applied to SMF services and -authorized to users, without actually applying them to users. - -Actions: - * create (default) - -Attributes: - * name - -Example: - -```ruby -rbac "nginx" do - action :create -end -``` - -This will update the authorizations file at `/etc/security/auth_attr` -with the following lines: - -``` -solaris.smf.manage.nginx:::Manage nginx Service States:: -solaris.smf.value.nginx:::Change value of nginx Service:: -``` - -Users who are given these authorizations can change properties of the -service as well as change its state (i.e. `svcadm disable|enable|restart|clear service` - -### rbac_auth - -Adds the rbac definition created by `auth` to the user `name`. - -Actions: - * add (default) - -Attributes: - * name - for descriptive purposes and to ensure that each LWRP call is uniquely - identified in the chef run - * user - * auth - -Example: - -```ruby -rbac_auth "add nginx management permissions to my_user" do - user "my_user" - auth "nginx" -end -``` - -This adds both manage and value auths to user `my_user`. - -## TODO - -* separate manage auth from value auth -* ability to delete all rbac attributes diff --git a/cookbooks/rbac/libraries/rbac.rb b/cookbooks/rbac/libraries/rbac.rb deleted file mode 100644 index 27b29a8..0000000 --- a/cookbooks/rbac/libraries/rbac.rb +++ /dev/null @@ -1,15 +0,0 @@ -# This module is used to retain state during the course of a chef -# run. The LWRPs in the cookbook modify a global hash in this module, -# and at the end of the chef run if user authorizations change they -# are written out into the system. -# -module RBAC - def self.authorizations - @authorizations ||= {} - end - - def self.add_authorization(username, auth) - authorizations[username] ||= [] - authorizations[username] << auth - end -end diff --git a/cookbooks/rbac/metadata.json b/cookbooks/rbac/metadata.json deleted file mode 100644 index 08c1d91..0000000 --- a/cookbooks/rbac/metadata.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "rbac", - "description": "Allows delegation of service management to users with Solaris Role Based Access Control (RBAC)", - "long_description": "Role based access control\n=========================\n\nSolaris and Illumos provide sophisticated role-based access control for\ndelegating authorizations within the system. Using RBAC, users can be\ngiven permissions to manage and update services without sudo.\n\nThis cookbook provides chef with LWRPs to manage RBAC and grant permissions.\n\nAt this time this cookbook ONLY manages SMF-related permissions (ie, ability\nof non-priviliged users to start/stop SMF services), but in the future it may\nbe enhanced to support arbitrary Solaris permissions.\n\n## Installation\n\nIn order to add the RBAC LWRPs to a chef run, add the following recipe \nto the run_list:\n\n rbac::default\n\nThis will do no work, but will load the providers.\n\n## LWRPs\n\n### rbac\n\nDefines a set of authorizations that can be applied to SMF services and\nauthorized to users, without actually applying them to users.\n\nActions:\n * create (default)\n\nAttributes:\n * name\n\nExample:\n\n```ruby\nrbac \"nginx\" do\n action :create\nend\n```\n\nThis will update the authorizations file at `/etc/security/auth_attr`\nwith the following lines:\n\n```\nsolaris.smf.manage.nginx:::Manage nginx Service States::\nsolaris.smf.value.nginx:::Change value of nginx Service::\n```\n\nUsers who are given these authorizations can change properties of the\nservice as well as change its state (i.e. `svcadm disable|enable|restart|clear service`\n\n### rbac_auth\n\nAdds the rbac definition created by `auth` to the user `name`.\n\nActions:\n * add (default)\n\nAttributes:\n * name - for descriptive purposes and to ensure that each LWRP call is uniquely\n identified in the chef run\n * user\n * auth\n\nExample:\n\n```ruby\nrbac_auth \"add nginx management permissions to my_user\" do\n user \"my_user\"\n auth \"nginx\"\nend\n```\n\nThis adds both manage and value auths to user `my_user`.\n\n## TODO\n\n* separate manage auth from value auth\n* ability to delete all rbac attributes\n", - "maintainer": "Eric Saxby", - "maintainer_email": "sax@livinginthepast.org", - "license": "MIT", - "platforms": { - "solaris2": ">= 0.0.0", - "smartos": ">= 0.0.0" - }, - "dependencies": { - - }, - "recommendations": { - - }, - "suggestions": { - - }, - "conflicting": { - - }, - "providing": { - - }, - "replacing": { - - }, - "attributes": { - - }, - "groupings": { - - }, - "recipes": { - - }, - "version": "1.0.3", - "source_url": "", - "issues_url": "" -} diff --git a/cookbooks/rbac/metadata.rb b/cookbooks/rbac/metadata.rb deleted file mode 100644 index 91c58d2..0000000 --- a/cookbooks/rbac/metadata.rb +++ /dev/null @@ -1,10 +0,0 @@ -name 'rbac' -maintainer 'Eric Saxby' -maintainer_email 'sax@livinginthepast.org' -license 'MIT' -description 'Allows delegation of service management to users with Solaris Role Based Access Control (RBAC)' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '1.0.3' - -supports 'solaris2' -supports 'smartos' diff --git a/cookbooks/rbac/providers/auth.rb b/cookbooks/rbac/providers/auth.rb deleted file mode 100644 index d922489..0000000 --- a/cookbooks/rbac/providers/auth.rb +++ /dev/null @@ -1,20 +0,0 @@ -def load_current_resource - @current_resource = Chef::Resource::RbacAuth.new(new_resource.name) - @new_resource.definition = run_context.resource_collection.find(:rbac => @new_resource.auth) - begin - @new_resource.user_definition = run_context.resource_collection.find(:rbac_user => @new_resource.user) - rescue Chef::Exceptions::ResourceNotFound - end -end - -action :add do - unless new_resource.user_definition - new_resource.user_definition = rbac_user new_resource.user - end - - new_resource.add_auth new_resource.user, new_resource.auth - - new_resource.updated_by_last_action(true) - - new_resource.notifies(:apply, new_resource.user_definition, :delayed) -end diff --git a/cookbooks/rbac/providers/default.rb b/cookbooks/rbac/providers/default.rb deleted file mode 100644 index 368de9e..0000000 --- a/cookbooks/rbac/providers/default.rb +++ /dev/null @@ -1,27 +0,0 @@ - -def load_current_resource - @current_resource = Chef::Resource::Rbac.new(@new_resource.name) -end - -action :create do - definition = new_resource.name - - new_resource.updated_by_last_action(false) - - manage_auth = "solaris.smf.manage.#{definition}:::Manage #{definition} Service States::" - manage = execute "add RBAC #{definition} management to /etc/security/auth_attr" do - command "echo \"#{manage_auth}\" >> /etc/security/auth_attr" - not_if "grep \"#{manage_auth}\" /etc/security/auth_attr" - end - - # This additional permission allows the user to call svccfg -s service setprop - # to set dynamic properties without having to re-run chef. This may be - # moved into a separate LWRP in the future. - value_auth = "solaris.smf.value.#{definition}:::Change value of #{definition} Service::" - value = execute "add RBAC #{definition} value to /etc/security/auth_attr" do - command "echo \"#{value_auth}\" >> /etc/security/auth_attr" - not_if "grep \"#{value_auth}\" /etc/security/auth_attr" - end - - new_resource.updated_by_last_action(manage.updated_by_last_action? || value.updated_by_last_action?) -end diff --git a/cookbooks/rbac/providers/user.rb b/cookbooks/rbac/providers/user.rb deleted file mode 100644 index cefb660..0000000 --- a/cookbooks/rbac/providers/user.rb +++ /dev/null @@ -1,22 +0,0 @@ -# The rbac_user LWRP is an internal set of classes used by other LWRPs to -# delay writing of user attributes until the end of the chef run. It should not be -# manually run. - -def load_current_resource - @current_resource = Chef::Resource::Rbac::User.new(@new_resource.user) -end - -action :apply do - username = new_resource.user - - auths = RBAC.authorizations[username] - permissions = auths.inject([]) do |auth, name| - auth + ["solaris.smf.manage.#{name}", "solaris.smf.value.#{name}"] - end.sort.uniq.join(',') - - execute "Apply rbac authorizations to #{username}" do - command "usermod -A #{permissions} #{username}" - action :nothing - not_if "grep #{username} /etc/user_attr | grep 'auths=#{permissions}'" - end.run_action(:run) -end diff --git a/cookbooks/rbac/recipes/default.rb b/cookbooks/rbac/recipes/default.rb deleted file mode 100644 index 3cab4b3..0000000 --- a/cookbooks/rbac/recipes/default.rb +++ /dev/null @@ -1,6 +0,0 @@ -# -# Cookbook Name:: rbac -# Recipe:: default -# -# Copyright 2012, ModCloth, Inc. -# diff --git a/cookbooks/rbac/resources/auth.rb b/cookbooks/rbac/resources/auth.rb deleted file mode 100644 index 4c8bedd..0000000 --- a/cookbooks/rbac/resources/auth.rb +++ /dev/null @@ -1,14 +0,0 @@ - -default_action :add - -actions :add - -attribute :user, :kind_of => String, :required => true -attribute :auth, :kind_of => String, :required => true - -# private, internal attributes -attr_accessor :definition, :user_definition - -def add_auth(user, auth) - RBAC.add_authorization(user, auth) -end diff --git a/cookbooks/rbac/resources/default.rb b/cookbooks/rbac/resources/default.rb deleted file mode 100644 index 8a56e0a..0000000 --- a/cookbooks/rbac/resources/default.rb +++ /dev/null @@ -1,6 +0,0 @@ - -default_action :create - -actions :create - -attribute :name, :kind_of => String, :name_attribute => true, :required => true diff --git a/cookbooks/rbac/resources/user.rb b/cookbooks/rbac/resources/user.rb deleted file mode 100644 index 25fb93c..0000000 --- a/cookbooks/rbac/resources/user.rb +++ /dev/null @@ -1,6 +0,0 @@ - -default_action :nothing - -actions :apply - -attribute :user, :kind_of => String, :name_attribute => true, :required => true diff --git a/cookbooks/smf/README.md b/cookbooks/smf/README.md deleted file mode 100644 index a1dabb0..0000000 --- a/cookbooks/smf/README.md +++ /dev/null @@ -1,370 +0,0 @@ -SMF -=== - -## Description - -Service Management Facility (SMF) is a tool in many Illumos and Solaris-derived operating systems -that treats services as first class objects of the system. It provides an XML syntax for -declaring how the system can interact with and control a service. - -The SMF cookbook contains providers for creating or modifying a service within the SMF framework. - - -## Requirements - -Any operating system that uses SMF, ie Solaris, SmartOS, OpenIndiana etc. - -The `smf` provider depends on the `builder` gem, which can be installed -via the `smf::default` recipe. - -Requires the RBAC cookbook, which can be found at . - -Processes can be run inside a project wrapper. In this case, look to the Resource Control cookbook, -which can be found at . Note that the SMF LWRP -does not create or manage the project. - - -## Basic Usage - -Note that we run the `smf::default` recipe before using LWRPs from this -cookbook. - -```ruby -include_recipe 'smf' - -smf 'my-service' do - user 'non-root-user' - start_command 'my-service start' - start_timeout 10 - stop_command 'pkill my-service' - stop_timeout 5 - restart_command 'my-service restart' - restart_timeout 60 - environment 'PATH' => '/home/non-root-user/bin', - 'RAILS_ENV' => 'staging' - locale 'C' - manifest_type 'application' - service_path '/var/svc/manifest' - notifies :restart, 'service[my-service]' -end - -service 'my-service' do - action :enable -end - -service 'my-service' do - action :restart -end -``` - - -## Attributes - -Ownership: -* `user` - User to run service commands as -* `group` - Group to run service commands as - -RBAC -* `authorization` - What management and value authorizations should be - created for this service. Defaults to the service name. - -Dependency management: -* `include_default_dependencies` - Service should depend on file system - and network services. Defaults to `true`. See [Dependencies](#dependencies) - for more info. -* `dependency` - an optional array of hashes signifying service and path - dependencies for this service to run. See [Dependencies](#dependencies). - -Process management: -* `project` - Name of project to run commands in -* `start_command` -* `start_timeout` -* `stop_command` - defaults to `:kill`, which basically means it will destroy every PID generated from the start command -* `stop_timeout` -* `restart_command` - defaults to `stop_command`, then `start_command` -* `restart_timeout` -* `refresh_command` - by default SMF treats this as `true`. This will be called when the SMF definition changes or - when a `notify :reload, 'service[thing]'` is called. -* `refresh_timeout` -* `duration` - Can be either `contract`, `wait`, `transient` or - `child`, but defaults to `contract`. See the [Duration](#duration) section below. -* `environment` - Hash - Environment variables to set while running commands -* `ignore` - Array - Faults to ignore in subprocesses. For example, - if core dumps in children are handled by a master process and you - don't want SMF thinking the service is exploding, you can ignore - ["core", "signal"]. -* `privileges` - Array - An array of privileges to be allowed for started processes. - Defaults to ['basic', 'net_privaddr'] -* `property_groups` - Hash - This should be in the form `{"group name" => {"type" => "application", "key" => "value", ...}}` -* `working_directory` - PWD that SMF should cd to in order to run commands -* `locale` - Character encoding to use (default "C") - -Manifest/FMRI metadata: -* `service_path` - defaults to `/var/svc/manifest` -* `manifest_type` - defaults to `application` -* `stability` - String - defaults to "Evolving". Valid options are - "Standard", "Stable", "Evolving", "Unstable", "External" and - "Obsolete" - -Deprecated: -* `credentials_user` - deprecated in favor of `user` - - -## Provider Actions - -### :install (default) - -This will drop a manifest XML file into `#{service_path}/#{manifest_type}/#{name}.xml`. If there is already a service -with a name that is matched by `new_resource.name` then the FMRI of our manifest will be set to the FMRI of the -pre-existing service. In this case, our properties will be merged into the properties of the pre-existing service. - -In this way, updates to recipes that use the SMF provider will not delete existing service properties, but will add -or overwrite them. - -Because of this, the SMF provider can be used to update properties for -services that are installed via a package manager. - -### :delete - -Remove an SMF definition. This stops the service if it is running. - -### :add_rbac - -This uses the `rbac` cookbook to define permissions that can then be applied to a user. This can be useful when local -users should manage services that are added via packages. - -```ruby -smf "nginx" do - action :add_rbac -end - -rbac_auth "Allow my user to manage nginx" do - user "my_user" - auth "nginx" -end -``` - - -## Resource Notes - -### `user`, `working_directory` and `environment` - -SMF does a remarkably good job running services as delegated users, and removes a lot of pain if you configure a -service correctly. There are many examples online (blogs, etc) of users wrapping their services in shell scripts with -`start`, `stop`, `restart` arguments. In general it seems as if the intention of these scripts is to take care of the -problem of setting environment variables and shelling out as another user. - -The use of init scripts to wrap executables can be unnecessary with SMF, as it provides hooks for all of these use cases. -When using `user`, SMF will assume that the `working_directory` is the user's home directory. This can be -easily overwritten (to `/home/user/app/current` for a Rails application, for example). One thing to be careful of is -that shell profile files will not be loaded. For this reason, if environment variables (such as PATH) are different -on your system or require additional entries arbitrary key/values may be set using the `environment` attribute. - -All things considered, one should think carefully about the need for an init script when working with SMF. For -well-behaved applications with simple configuration, an init script is overkill. Applications with endless command-line -options or that need a real login shell (for instance ruby applications that use RVM) an init script may make life -easier. - -### Role Based Authorization - -By default the SMF definition creates authorizations based on the -service name. The service user is then granted these authorizations. If -the service is named `asplosions`, then `solaris.smf.manage.asplosions` -and `solaris.smf.value.asplosions` will be created. - -The authorization can be changed by manually setting `authorization` on -the smf block: - -```ruby -smf 'asplosions' do - user 'monkeyking' - start_command 'asplode' - authorization 'booms' -end -``` - -This can be helpful if there are many services configured on a single -host, as multiple services can be collapsed into the same -authorizations. For instance: https://illumos.org/issues/4968 - -### Dependencies - -SMF allows services to explicitly list their dependencies on other -services. Among other things, this ensures that services are enabled in -the proper order on boot, so that a service doesn't fail to start -because another service has not yet been started. - -By default, services created by the SMF LWRP depend on the following other services: -* svc:/milestone/sysconfig -* svc:/system/filesystem/local -* svc:/milestone/name-services -* svc:/milestone/network - -On Solaris11, `svc:/milestone/sysconfig` is replaced with -`svc:/milestone/config`. - -These are configured with the attribute `include_default_dependencies`, -which defaults to `true`. - -Other dependencies can be specified with the `dependencies` attribute, -which takes an array of hashes as follows: - -```ruby -smf 'redis' - -smf 'redis-6999' do - start_command "..." - dependencies [ - {name: 'redis', fmris: ['svc:/application/management/redis'], - grouping: 'require_all', restart_on: 'restart', type: 'service'} - ] -end -``` - -Valid options for grouping: -* require_all - All listed FMRIs must be online -* require_any - Any of the listed FMRIs must be online -* exclude_all - None of the listed FMRIs can be online -* optional_all - FMRIs are either online or unable to come online - -Valid options for restart_on: -* error - Hardware fault -* restart - Restarts service if the depedency is restarted -* refresh - Restarted if the dependency is restarted or refreshed for - any reason -* none - Don't do anything - -Valid options for type: -* service - expects dependency FMRIs to be other services ie: svc:/type/of/service:instance -* path - expects FMRIs to be paths, ie file://localhost/etc/redis/redis.conf - -Note: the provider currently does not do any validation of these values. Also, type:path has not been extensively -tested. Use this at your own risk, or improve the provider's compatibility with type:path and submit a pull request! - -### Duration - -There are several different ways that SMF can track your service. By default it uses `contract`. -Basically, this means that it will keep track of the PIDs of all daemonized processes generated from `start_command`. -If SMF sees that processes are cycling, it may try to restart the service. If things get too hectic, it -may think that your service is flailing and put it into maintenance mode. If this is normal for your service, -for instance if you have a master that occasionally reaps processes, you may want to specify additional -configuration options. - -If you have a job that you want managed by SMF, but which is not daemonized, another duration option is -`transient`. In this mode, SMF will not watch any processes, but will expect that the main process exits cleanly. -This can be used, for instance, for a script that must be run at boot time, or for a script that you want to delegate -to particular users with Role Based Access Control. In this case, the script can be registered with SMF to run as root, -but with the start_command delegated to your user. - -A third option is `wait`. This covers non-daemonized processes. - -A fourth option is `child`. - -### Ignore - -Sometimes you have a case where your service behaves poorly. The Ruby server Unicorn, for example, has a master -process that likes to kill its children. This causes core dumps that SMF will interpret to be a failing service. -Instead you can `ignore ["core", "signal"]` and SMF will stop caring about core dumps. - -### Privileges - -Some system calls require privileges generally only granted to superusers or particular roles. In Solaris, an -SMF definition can also set specific privileges for contracted processes. - -By default the SMF provider will grant 'basic' and 'net_privaddr' permissions, but this can be set as follows: - -```ruby -smf 'elasticsearch' do - start_command 'elasticsearch' - privileges ['basic', 'proc_lock_memory'] -end -``` - -See the (privileges man page)[https://www.illumos.org/man/5/privileges] for more information. - -### Property Groups - -Property Groups are where you can store extra information for SMF to use later. They should be used in the -following format: - -```ruby -smf "my-service" do - start_command "do-something" - property_groups({ - "config" => { - "type" => "application", - "my-property" => "property value" - } - }) -end -``` - -`type` will default to `application`, and is used in the manifest XML to declare how the property group will be -used. For this reason, `type` can not be used as a property name (ie variable). - -One way to use property groups is to pass variables on to commands, as follows: - -```ruby -rails_env = node["from-chef-environment"]["rails-env"] - -smf "unicorn" do - start_command "bundle exec unicorn_rails -c /home/app_user/app/current/config/%{config/rails_env} -E %{config/rails_env} -D" - start_timeout 300 - restart_command ":kill -SIGUSR2" - restart_timeout 300 - working_directory "/home/app_user/app/current" - property_groups({ - "config" => { - "rails_env" => rails_env - } - }) -end -``` - -This is especially handy if you have a case where your commands may come from role attributes, but can -only work if they have access to variables set in an environment or computed in a recipe. - -### Stability - -This is for reference more than anything, so that administrators of a service know what to expect of possible changes to -the service definition. - -See: - - -## Working Examples - -Please see the [examples](https://github.com/livinginthepast/smf/blob/master/EXAMPLES.md) page for -example usages. - - -## Cookbook upgrades, possible side effects - -Changes to this cookbook may change the way that its internal checksums are generated for a service. -If you `notify :restart` any service from within the `smf` block or include a `refresh_command`, please -be aware that upgrading this cookbook may trigger a refresh or a registered notification on the first -subsequent chef run. - -## Contributing - -* fork -* file an issue to track updates/communication -* add tests -* rebase master into your branch -* issue a pull request - -Please do not increment the cookbook version in a fork. Version updates -will be done on the master branch after any pull requests are merged. - -When upstream changes are added to the master branch while you are -working on a contribution, please rebase master into your branch and -force push. A pull request should be able to be merged through a -fast-forward, without a merge commit. - -## Testing - -```bash -bundle -vagrant plugin install vagrant-smartos-zones -bundle exec strainer test -``` diff --git a/cookbooks/smf/libraries/helper.rb b/cookbooks/smf/libraries/helper.rb deleted file mode 100644 index ab2b0c6..0000000 --- a/cookbooks/smf/libraries/helper.rb +++ /dev/null @@ -1,9 +0,0 @@ -unless defined?(SMFManifest::Helper) - module SMFManifest - # Generic helper that other helpers can inherit from. - # Takes the current node object, as well as an optional - # resource. - class Helper < Struct.new(:node, :resource) - end - end -end diff --git a/cookbooks/smf/libraries/matchers.rb b/cookbooks/smf/libraries/matchers.rb deleted file mode 100644 index e0242e3..0000000 --- a/cookbooks/smf/libraries/matchers.rb +++ /dev/null @@ -1,9 +0,0 @@ -if defined?(ChefSpec) - def install_smf(name) - ChefSpec::Matchers::ResourceMatcher.new(:smf, :install, name) - end - - def delete_smf(name) - ChefSpec::Matchers::ResourceMatcher.new(:smf, :delete, name) - end -end diff --git a/cookbooks/smf/libraries/rbac_helper.rb b/cookbooks/smf/libraries/rbac_helper.rb deleted file mode 100644 index 6461afe..0000000 --- a/cookbooks/smf/libraries/rbac_helper.rb +++ /dev/null @@ -1,31 +0,0 @@ -module SMFManifest - # Helper methods for determining whether work needs to be done - # with respect to assigning RBAC values to a service. - class RBACHelper < SMFManifest::Helper - include Chef::Mixin::ShellOut - - def authorization_set? - current_authorization == authorization - end - - def value_authorization_set? - current_value_authorization == value_authorization - end - - def current_authorization - shell_out("svcprop -p general/action_authorization #{resource.name}").stdout.chomp - end - - def current_value_authorization - shell_out("svcprop -p general/value_authorization #{resource.name}").stdout.chomp - end - - def authorization - "solaris.smf.manage.#{resource.authorization_name}" - end - - def value_authorization - "solaris.smf.value.#{resource.authorization_name}" - end - end -end diff --git a/cookbooks/smf/libraries/xml_builder.rb b/cookbooks/smf/libraries/xml_builder.rb deleted file mode 100644 index a9b7f7f..0000000 --- a/cookbooks/smf/libraries/xml_builder.rb +++ /dev/null @@ -1,209 +0,0 @@ -## This is kind of a hack, to ensure that the cookbook can be -# loaded. On first load, nokogiri may not be present. It is -# installed at load time by recipes/default.rb, so that at run -# time nokogiri will be present. -# -require 'forwardable' - -# rubocop:disable Metrics/ClassLength -module SMFManifest - # XMLBuilder manages the translation of the SMF Chef resource attributes into - # XML that can be parsed by `svccfg import`. - # - # SMFManifest::XMLBuilder.new(resource, node).to_xml - # - class XMLBuilder - # allow delegation - extend Forwardable - - attr_reader :resource, :node - - # delegate methods to :resource - def_delegators :resource, :name, :authorization_name, :dependencies, :duration, :environment, :group, :ignore, - :include_default_dependencies, :locale, :manifest_type, :project, :property_groups, - :service_path, :stability, :working_directory - - public - - def initialize(smf_resource, node) - @resource = smf_resource - @node = node - end - - def to_xml - @xml_output ||= xml_output - end - - protected - - ## methods that need to be called from within the context - # of the Nokogiri builder block need to be protected, rather - # than private. - - def commands - @commands ||= { - 'start' => resource.start_command, - 'stop' => resource.stop_command, - 'restart' => resource.restart_command, - 'refresh' => resource.refresh_command - } - end - - def timeout - @timeouts ||= { - 'start' => resource.start_timeout, - 'stop' => resource.stop_timeout, - 'restart' => resource.restart_timeout, - 'refresh' => resource.refresh_timeout - } - end - - def default_dependencies - if node.platform == 'solaris2' && node.platform_version == '5.11' - [ - { 'name' => 'milestone', 'value' => '/milestone/config' }, - { 'name' => 'fs-local', 'value' => '/system/filesystem/local' }, - { 'name' => 'name-services', 'value' => '/milestone/name-services' }, - { 'name' => 'network', 'value' => '/milestone/network' } - ] - else - [ - { 'name' => 'milestone', 'value' => '/milestone/sysconfig' }, - { 'name' => 'fs-local', 'value' => '/system/filesystem/local' }, - { 'name' => 'name-services', 'value' => '/milestone/name-services' }, - { 'name' => 'network', 'value' => '/milestone/network' } - ] - end - end - - private - - def xml_output - xml_builder = ::Builder::XmlMarkup.new(indent: 2) - xml_builder.instruct! - xml_builder.declare! :DOCTYPE, :service_bundle, :SYSTEM, '/usr/share/lib/xml/dtd/service_bundle.dtd.1' - xml_builder.service_bundle('name' => name, 'type' => 'manifest') do |xml| - xml.service('name' => service_fmri, 'type' => 'service', 'version' => '1') do |service| - service.create_default_instance('enabled' => 'false') - service.single_instance - - if include_default_dependencies - default_dependencies.each do |dependency| - service.dependency('name' => dependency['name'], - 'grouping' => 'require_all', - 'restart_on' => 'none', - 'type' => 'service') do |dep| - dep.service_fmri('value' => "svc:#{dependency['value']}") - end - end - end - - dependencies.each do |dependency| - service.dependency('name' => dependency['name'], - 'grouping' => dependency['grouping'], - 'restart_on' => dependency['restart_on'], - 'type' => dependency['type']) do |dep| - dependency['fmris'].each do |service_fmri| - dep.service_fmri('value' => service_fmri) - end - end - end - - service.method_context(exec_context) do |context| - context.method_credential(credentials) if user != 'root' - - if environment - context.method_environment do |env| - environment.each_pair do |var, value| - env.envvar('name' => var, 'value' => value) - end - end - end - end - - commands.each_pair do |type, command| - if command - service.exec_method('type' => 'method', 'name' => type, 'exec' => command, 'timeout_seconds' => timeout[type]) - end - end - - service.property_group('name' => 'general', 'type' => 'framework') do |group| - group.propval('name' => 'action_authorization', - 'type' => 'astring', - 'value' => "solaris.smf.manage.#{authorization_name}") - group.propval('name' => 'value_authorization', - 'type' => 'astring', - 'value' => "solaris.smf.value.#{authorization_name}") - end - - if sets_duration? || ignores_faults? - service.property_group('name' => 'startd', 'type' => 'framework') do |group| - group.propval('name' => 'duration', 'type' => 'astring', 'value' => duration) if sets_duration? - group.propval('name' => 'ignore_error', 'type' => 'astring', 'value' => ignore.join(',')) if ignores_faults? - end - end - - property_groups.each_pair do |name, properties| - service.property_group('name' => name, 'type' => properties.delete('type') { |_type| 'application' }) do |group| - properties.each_pair do |key, value| - group.propval('name' => key, 'value' => value, 'type' => check_type(value)) - end - end - end - - service.stability('value' => stability) - - service.template do |template| - template.common_name do |common_name| - common_name.loctext(name, 'xml:lang' => locale) - end - end - end - end - - xml_builder.target! - end - - def credentials - creds = { 'user' => user, 'privileges' => resource.privilege_list } - creds.merge!('group' => group) unless group.nil? - creds - end - - def user - resource.user || resource.credentials_user || 'root' - end - - def exec_context - context = {} - context['working_directory'] = working_directory unless working_directory.nil? - context['project'] = project unless project.nil? - context - end - - def check_type(value) - if value == value.to_i - 'integer' - else - 'astring' - end - end - - def ignores_faults? - !ignore.nil? - end - - def sets_duration? - duration != 'contract' - end - - # resource.fmri is set in the SMF :install action of the default provider. - # If there is already a service with a name that is matched by our resource.name - # then we grab the FMRI (fault management resource identifier) from the system. - # If a service is not found, we set this to our own FMRI. - def service_fmri - resource.fmri.nil? || resource.fmri.empty? ? "#{manifest_type}/management/#{name}" : resource.fmri.gsub(/^\//, '') - end - end -end -# rubocop:enable Metrics/ClassLength diff --git a/cookbooks/smf/metadata.json b/cookbooks/smf/metadata.json deleted file mode 100644 index d5aba81..0000000 --- a/cookbooks/smf/metadata.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "smf", - "description": "A light weight resource provider (LWRP) for SMF (Service Management Facility)", - "long_description": "SMF\n===\n\n## Description\n\nService Management Facility (SMF) is a tool in many Illumos and Solaris-derived operating systems\nthat treats services as first class objects of the system. It provides an XML syntax for \ndeclaring how the system can interact with and control a service.\n\nThe SMF cookbook contains providers for creating or modifying a service within the SMF framework.\n\n\n## Requirements\n\nAny operating system that uses SMF, ie Solaris, SmartOS, OpenIndiana etc.\n\nThe `smf` provider depends on the `builder` gem, which can be installed\nvia the `smf::default` recipe.\n\nRequires the RBAC cookbook, which can be found at .\n\nProcesses can be run inside a project wrapper. In this case, look to the Resource Control cookbook,\nwhich can be found at . Note that the SMF LWRP\ndoes not create or manage the project.\n\n\n## Basic Usage\n\nNote that we run the `smf::default` recipe before using LWRPs from this\ncookbook.\n\n```ruby\ninclude_recipe 'smf'\n\nsmf 'my-service' do\n user 'non-root-user'\n start_command 'my-service start'\n start_timeout 10\n stop_command 'pkill my-service'\n stop_timeout 5\n restart_command 'my-service restart'\n restart_timeout 60\n environment 'PATH' => '/home/non-root-user/bin',\n 'RAILS_ENV' => 'staging'\n locale 'C'\n manifest_type 'application'\n service_path '/var/svc/manifest'\n notifies :restart, 'service[my-service]'\nend\n\nservice 'my-service' do\n action :enable\nend\n\nservice 'my-service' do\n action :restart\nend\n```\n\n\n## Attributes\n\nOwnership:\n* `user` - User to run service commands as\n* `group` - Group to run service commands as\n\nRBAC\n* `authorization` - What management and value authorizations should be\n created for this service. Defaults to the service name.\n\nDependency management:\n* `include_default_dependencies` - Service should depend on file system\n and network services. Defaults to `true`. See [Dependencies](#dependencies)\n for more info.\n* `dependency` - an optional array of hashes signifying service and path\n dependencies for this service to run. See [Dependencies](#dependencies).\n\nProcess management:\n* `project` - Name of project to run commands in\n* `start_command`\n* `start_timeout`\n* `stop_command` - defaults to `:kill`, which basically means it will destroy every PID generated from the start command\n* `stop_timeout`\n* `restart_command` - defaults to `stop_command`, then `start_command`\n* `restart_timeout`\n* `refresh_command` - by default SMF treats this as `true`. This will be called when the SMF definition changes or\n when a `notify :reload, 'service[thing]'` is called.\n* `refresh_timeout`\n* `duration` - Can be either `contract`, `wait`, `transient` or\n `child`, but defaults to `contract`. See the [Duration](#duration) section below.\n* `environment` - Hash - Environment variables to set while running commands\n* `ignore` - Array - Faults to ignore in subprocesses. For example, \n if core dumps in children are handled by a master process and you \n don't want SMF thinking the service is exploding, you can ignore \n [\"core\", \"signal\"].\n* `privileges` - Array - An array of privileges to be allowed for started processes.\n Defaults to ['basic', 'net_privaddr']\n* `property_groups` - Hash - This should be in the form `{\"group name\" => {\"type\" => \"application\", \"key\" => \"value\", ...}}`\n* `working_directory` - PWD that SMF should cd to in order to run commands\n* `locale` - Character encoding to use (default \"C\")\n\nManifest/FMRI metadata:\n* `service_path` - defaults to `/var/svc/manifest`\n* `manifest_type` - defaults to `application`\n* `stability` - String - defaults to \"Evolving\". Valid options are\n \"Standard\", \"Stable\", \"Evolving\", \"Unstable\", \"External\" and\n \"Obsolete\"\n\nDeprecated:\n* `credentials_user` - deprecated in favor of `user`\n\n\n## Provider Actions\n\n### :install (default)\n\nThis will drop a manifest XML file into `#{service_path}/#{manifest_type}/#{name}.xml`. If there is already a service\nwith a name that is matched by `new_resource.name` then the FMRI of our manifest will be set to the FMRI of the \npre-existing service. In this case, our properties will be merged into the properties of the pre-existing service.\n\nIn this way, updates to recipes that use the SMF provider will not delete existing service properties, but will add \nor overwrite them.\n\nBecause of this, the SMF provider can be used to update properties for\nservices that are installed via a package manager.\n\n### :delete\n\nRemove an SMF definition. This stops the service if it is running.\n\n### :add_rbac\n\nThis uses the `rbac` cookbook to define permissions that can then be applied to a user. This can be useful when local\nusers should manage services that are added via packages.\n\n```ruby\nsmf \"nginx\" do\n action :add_rbac\nend\n\nrbac_auth \"Allow my user to manage nginx\" do\n user \"my_user\"\n auth \"nginx\"\nend\n```\n\n\n## Resource Notes\n\n### `user`, `working_directory` and `environment`\n\nSMF does a remarkably good job running services as delegated users, and removes a lot of pain if you configure a \nservice correctly. There are many examples online (blogs, etc) of users wrapping their services in shell scripts with \n`start`, `stop`, `restart` arguments. In general it seems as if the intention of these scripts is to take care of the\nproblem of setting environment variables and shelling out as another user.\n\nThe use of init scripts to wrap executables can be unnecessary with SMF, as it provides hooks for all of these use cases. \nWhen using `user`, SMF will assume that the `working_directory` is the user's home directory. This can be\neasily overwritten (to `/home/user/app/current` for a Rails application, for example). One thing to be careful of is \nthat shell profile files will not be loaded. For this reason, if environment variables (such as PATH) are different \non your system or require additional entries arbitrary key/values may be set using the `environment` attribute.\n\nAll things considered, one should think carefully about the need for an init script when working with SMF. For \nwell-behaved applications with simple configuration, an init script is overkill. Applications with endless command-line \noptions or that need a real login shell (for instance ruby applications that use RVM) an init script may make life\neasier.\n\n### Role Based Authorization\n\nBy default the SMF definition creates authorizations based on the\nservice name. The service user is then granted these authorizations. If\nthe service is named `asplosions`, then `solaris.smf.manage.asplosions`\nand `solaris.smf.value.asplosions` will be created.\n\nThe authorization can be changed by manually setting `authorization` on\nthe smf block:\n\n```ruby\nsmf 'asplosions' do\n user 'monkeyking'\n start_command 'asplode'\n authorization 'booms'\nend\n```\n\nThis can be helpful if there are many services configured on a single\nhost, as multiple services can be collapsed into the same\nauthorizations. For instance: https://illumos.org/issues/4968 \n\n### Dependencies\n\nSMF allows services to explicitly list their dependencies on other\nservices. Among other things, this ensures that services are enabled in\nthe proper order on boot, so that a service doesn't fail to start\nbecause another service has not yet been started.\n\nBy default, services created by the SMF LWRP depend on the following other services:\n* svc:/milestone/sysconfig\n* svc:/system/filesystem/local\n* svc:/milestone/name-services\n* svc:/milestone/network\n\nOn Solaris11, `svc:/milestone/sysconfig` is replaced with\n`svc:/milestone/config`.\n\nThese are configured with the attribute `include_default_dependencies`,\nwhich defaults to `true`.\n\nOther dependencies can be specified with the `dependencies` attribute,\nwhich takes an array of hashes as follows:\n\n```ruby\nsmf 'redis'\n\nsmf 'redis-6999' do\n start_command \"...\"\n dependencies [\n {name: 'redis', fmris: ['svc:/application/management/redis'],\n grouping: 'require_all', restart_on: 'restart', type: 'service'}\n ]\nend\n```\n\nValid options for grouping:\n* require_all - All listed FMRIs must be online\n* require_any - Any of the listed FMRIs must be online\n* exclude_all - None of the listed FMRIs can be online\n* optional_all - FMRIs are either online or unable to come online\n\nValid options for restart_on:\n* error - Hardware fault\n* restart - Restarts service if the depedency is restarted\n* refresh - Restarted if the dependency is restarted or refreshed for\n any reason\n* none - Don't do anything\n\nValid options for type:\n* service - expects dependency FMRIs to be other services ie: svc:/type/of/service:instance\n* path - expects FMRIs to be paths, ie file://localhost/etc/redis/redis.conf\n\nNote: the provider currently does not do any validation of these values. Also, type:path has not been extensively\ntested. Use this at your own risk, or improve the provider's compatibility with type:path and submit a pull request!\n\n### Duration\n\nThere are several different ways that SMF can track your service. By default it uses `contract`. \nBasically, this means that it will keep track of the PIDs of all daemonized processes generated from `start_command`.\nIf SMF sees that processes are cycling, it may try to restart the service. If things get too hectic, it\nmay think that your service is flailing and put it into maintenance mode. If this is normal for your service,\nfor instance if you have a master that occasionally reaps processes, you may want to specify additional\nconfiguration options.\n\nIf you have a job that you want managed by SMF, but which is not daemonized, another duration option is\n`transient`. In this mode, SMF will not watch any processes, but will expect that the main process exits cleanly.\nThis can be used, for instance, for a script that must be run at boot time, or for a script that you want to delegate\nto particular users with Role Based Access Control. In this case, the script can be registered with SMF to run as root,\nbut with the start_command delegated to your user.\n\nA third option is `wait`. This covers non-daemonized processes.\n\nA fourth option is `child`.\n\n### Ignore\n\nSometimes you have a case where your service behaves poorly. The Ruby server Unicorn, for example, has a master \nprocess that likes to kill its children. This causes core dumps that SMF will interpret to be a failing service.\nInstead you can `ignore [\"core\", \"signal\"]` and SMF will stop caring about core dumps.\n\n### Privileges\n\nSome system calls require privileges generally only granted to superusers or particular roles. In Solaris, an\nSMF definition can also set specific privileges for contracted processes.\n\nBy default the SMF provider will grant 'basic' and 'net_privaddr' permissions, but this can be set as follows:\n\n```ruby\nsmf 'elasticsearch' do\n start_command 'elasticsearch'\n privileges ['basic', 'proc_lock_memory']\nend\n```\n\nSee the (privileges man page)[https://www.illumos.org/man/5/privileges] for more information.\n\n### Property Groups\n\nProperty Groups are where you can store extra information for SMF to use later. They should be used in the\nfollowing format:\n\n```ruby\nsmf \"my-service\" do\n start_command \"do-something\"\n property_groups({\n \"config\" => {\n \"type\" => \"application\",\n \"my-property\" => \"property value\"\n }\n })\nend\n```\n\n`type` will default to `application`, and is used in the manifest XML to declare how the property group will be\nused. For this reason, `type` can not be used as a property name (ie variable).\n\nOne way to use property groups is to pass variables on to commands, as follows:\n\n```ruby\nrails_env = node[\"from-chef-environment\"][\"rails-env\"]\n\nsmf \"unicorn\" do\n start_command \"bundle exec unicorn_rails -c /home/app_user/app/current/config/%{config/rails_env} -E %{config/rails_env} -D\"\n start_timeout 300\n restart_command \":kill -SIGUSR2\"\n restart_timeout 300\n working_directory \"/home/app_user/app/current\"\n property_groups({\n \"config\" => {\n \"rails_env\" => rails_env\n }\n })\nend\n```\n\nThis is especially handy if you have a case where your commands may come from role attributes, but can\nonly work if they have access to variables set in an environment or computed in a recipe.\n\n### Stability\n\nThis is for reference more than anything, so that administrators of a service know what to expect of possible changes to \nthe service definition.\n\nSee: \n\n\n## Working Examples\n\nPlease see the [examples](https://github.com/livinginthepast/smf/blob/master/EXAMPLES.md) page for\nexample usages.\n\n\n## Cookbook upgrades, possible side effects\n\nChanges to this cookbook may change the way that its internal checksums are generated for a service.\nIf you `notify :restart` any service from within the `smf` block or include a `refresh_command`, please\nbe aware that upgrading this cookbook may trigger a refresh or a registered notification on the first\nsubsequent chef run.\n\n## Contributing\n\n* fork\n* file an issue to track updates/communication\n* add tests\n* rebase master into your branch\n* issue a pull request\n\nPlease do not increment the cookbook version in a fork. Version updates\nwill be done on the master branch after any pull requests are merged.\n\nWhen upstream changes are added to the master branch while you are\nworking on a contribution, please rebase master into your branch and\nforce push. A pull request should be able to be merged through a\nfast-forward, without a merge commit.\n\n## Testing\n\n```bash\nbundle\nvagrant plugin install vagrant-smartos-zones\nbundle exec strainer test\n```\n", - "maintainer": "Eric Saxby", - "maintainer_email": "sax@livinginthepast.org", - "license": "MIT", - "platforms": { - "smartos": ">= 0.0.0" - }, - "dependencies": { - "rbac": ">= 1.0.1" - }, - "recommendations": { - - }, - "suggestions": { - "resource-control": ">= 0.0.0" - }, - "conflicting": { - - }, - "providing": { - - }, - "replacing": { - - }, - "attributes": { - - }, - "groupings": { - - }, - "recipes": { - - }, - "version": "2.2.8", - "source_url": "", - "issues_url": "", - "privacy": false, - "chef_versions": [ - - ], - "ohai_versions": [ - - ] -} diff --git a/cookbooks/smf/metadata.rb b/cookbooks/smf/metadata.rb deleted file mode 100644 index 94a4751..0000000 --- a/cookbooks/smf/metadata.rb +++ /dev/null @@ -1,13 +0,0 @@ -name 'smf' -maintainer 'Eric Saxby' -maintainer_email 'sax@livinginthepast.org' -license 'MIT' -description 'A light weight resource provider (LWRP) for SMF (Service Management Facility)' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '2.2.8' - -supports 'smartos' - -depends 'rbac', '>= 1.0.1' - -suggests 'resource-control' # For managing Solaris projects, when setting project on a manifest diff --git a/cookbooks/smf/providers/default.rb b/cookbooks/smf/providers/default.rb deleted file mode 100644 index 76670e1..0000000 --- a/cookbooks/smf/providers/default.rb +++ /dev/null @@ -1,143 +0,0 @@ - -require 'chef/mixin/shell_out' -require 'fileutils' -include Chef::Mixin::ShellOut - -def load_current_resource - find_fmri unless new_resource.fmri - - @current_resource = Chef::Resource::Smf.new(new_resource.name) - @current_resource.fmri(new_resource.fmri) - @current_resource.load -end - -action :install do - create_directories - write_manifest - create_rbac_definitions - import_manifest - deduplicate_manifest - add_rbac_permissions - - new_resource.updated_by_last_action(smf_changed?) - new_resource.save_checksum if smf_changed? -end - -action :add_rbac do - create_rbac_definitions - service new_resource.name - - manage = execute "add SMF authorization to allow RBAC for #{new_resource.name}" do - command "svccfg -s #{new_resource.name} " \ - 'setprop general/action_authorization=astring:' \ - "'solaris.smf.manage.#{new_resource.authorization_name}'" - not_if { SMFManifest::RBACHelper.new(node, new_resource).authorization_set? } - notifies :reload, "service[#{new_resource.name}]" - end - - value = execute "add SMF value to allow RBAC for #{new_resource.name}" do - command "svccfg -s #{new_resource.name} " \ - 'setprop general/value_authorization=astring: ' \ - 'solaris.smf.value.#{new_resource.authorization_name}' - not_if { SMFManifest::RBACHelper.new(node, new_resource).value_authorization_set? } - notifies :reload, "service[#{new_resource.name}]" - end - - new_resource.updated_by_last_action(manage.updated_by_last_action? || value.updated_by_last_action?) -end - -action :delete do - new_resource.updated_by_last_action(false) - - if @current_resource.smf_exists? - service new_resource.name do - action [:stop, :disable] - end - - execute "remove service #{new_resource.name} from SMF" do - command "svccfg delete #{new_resource.name}" - end - - delete_manifest - new_resource.remove_checksum - - new_resource.updated_by_last_action(true) - end -end - -private - -def smf_changed? - @current_resource.checksum != new_resource.checksum || !@current_resource.smf_exists? -end - -def find_fmri - fmri_check = shell_out(%(svcs -H -o FMRI #{new_resource.name})) - if fmri_check.exitstatus == 0 - new_resource.fmri fmri_check.stdout.chomp.split(':')[1] - else - new_resource.fmri "/#{new_resource.manifest_type}/management/#{new_resource.name}" - end -end - -def create_directories - Chef::Log.debug "Creating manifest directory at #{new_resource.xml_path}" - FileUtils.mkdir_p new_resource.xml_path -end - -def write_manifest - return unless smf_changed? - - Chef::Log.debug "Writing SMF manifest for #{new_resource.name}" - ::File.open(new_resource.xml_file, 'w') do |file| - file.puts SMFManifest::XMLBuilder.new(new_resource, node).to_xml - end -end - -def delete_manifest - return unless ::File.exist?(new_resource.xml_file) - - Chef::Log.debug "Removing SMF manifest for #{new_resource.name}" - ::File.delete(new_resource.xml_file) -end - -def create_rbac_definitions - rbac new_resource.authorization_name do - action :create - end -end - -def add_rbac_permissions - user = new_resource.user || new_resource.credentials_user || 'root' - - rbac_auth "Add RBAC for #{new_resource.name} to #{user}" do - user user - auth new_resource.authorization_name - not_if { user == 'root' } - end -end - -def import_manifest - return unless smf_changed? - - Chef::Log.debug("importing SMF manifest #{new_resource.xml_file}") - shell_out!("svccfg import #{new_resource.xml_file}") -end - -def deduplicate_manifest - # If we are overwriting properties from an old SMF definition (from pkgsrc, etc) - # there may be redundant XML files that we want to dereference - name = new_resource.name - - duplicate_manifest = shell_out("svcprop #{name} | grep -c manifestfiles").stdout.strip.to_i > 1 - return unless duplicate_manifest - - Chef::Log.debug "Removing duplicate SMF manifest reference from #{name}" - shell_out! "svccfg -s #{name} delprop " \ - "`svcprop #{name} | grep manifestfiles | grep -v #{new_resource.xml_file} | awk '{ print $1 }'` " \ - "&& svcadm refresh #{name}" -end - -def smf_defined?(fmri) - shell_out("svcs #{fmri}").exitstatus == 0 -end diff --git a/cookbooks/smf/recipes/SMFServicesOK.rb b/cookbooks/smf/recipes/SMFServicesOK.rb deleted file mode 100644 index d3f5c1f..0000000 --- a/cookbooks/smf/recipes/SMFServicesOK.rb +++ /dev/null @@ -1,25 +0,0 @@ -directory '/opt/scripts' do - action :create - mode '0755' - owner 'root' - group 'root' -end - -directory '/opt/local/etc/snmp/conf.d' do - action :create - mode '0755' - owner 'root' - group 'root' -end - -template '/opt/scripts/SMFServicesOK.sh' do - path '/opt/scripts/SMFServicesOK.sh' - source 'SMFServicesOK.sh.erb' - mode '0755' -end - -template 'SMFServicesOK.snmpd.conf' do - path '/opt/local/etc/snmp/conf.d/SMFServicesOK.snmpd.conf' - source 'SMFServicesOK.snmpd.conf.erb' - mode '0644' -end diff --git a/cookbooks/smf/recipes/default.rb b/cookbooks/smf/recipes/default.rb deleted file mode 100644 index 72d8f16..0000000 --- a/cookbooks/smf/recipes/default.rb +++ /dev/null @@ -1,7 +0,0 @@ -## These libraries need to be installed when the cookbook -# is loaded, otherwise they are not available when the -# cookbook runs. - -chef_gem 'builder' - -require 'builder' diff --git a/cookbooks/smf/resources/default.rb b/cookbooks/smf/resources/default.rb deleted file mode 100644 index 6224e19..0000000 --- a/cookbooks/smf/resources/default.rb +++ /dev/null @@ -1,124 +0,0 @@ - -require 'chef/mixin/shell_out' -include Chef::Mixin::ShellOut - -actions :install, :add_rbac, :delete -default_action :install - -attribute :name, kind_of: String, name_attribute: true, required: true -attribute :user, kind_of: [String, NilClass], default: nil -attribute :group, kind_of: [String, NilClass], default: nil -attribute :project, kind_of: [String, NilClass], default: nil - -attribute :authorization, kind_of: [String, NilClass], default: nil - -attribute :start_command, kind_of: [String, NilClass], default: nil -attribute :start_timeout, kind_of: Integer, default: 5 -attribute :stop_command, kind_of: String, default: ':kill' -attribute :stop_timeout, kind_of: Integer, default: 5 -attribute :restart_command, kind_of: [String, NilClass], default: nil -attribute :restart_timeout, kind_of: Integer, default: 5 -attribute :refresh_command, kind_of: [String, NilClass], default: nil -attribute :refresh_timeout, kind_of: Integer, default: 5 - -attribute :include_default_dependencies, kind_of: [TrueClass, FalseClass], default: true -attribute :dependencies, kind_of: [Array], default: [] - -attribute :privileges, kind_of: [Array], default: %w(basic net_privaddr) -attribute :working_directory, kind_of: [String, NilClass], default: nil -attribute :environment, kind_of: [Hash, NilClass], default: nil -attribute :locale, kind_of: String, default: 'C' - -attribute :manifest_type, kind_of: String, default: 'application' -attribute :service_path, kind_of: String, default: '/var/svc/manifest' - -attribute :duration, kind_of: String, default: 'contract', regex: '(contract|wait|transient|child)' -attribute :ignore, kind_of: [Array, NilClass], default: nil -attribute :fmri, kind_of: String, default: nil - -attribute :stability, kind_of: String, equal_to: %w(Standard Stable Evolving Unstable External Obsolete), - default: 'Evolving' - -attribute :property_groups, kind_of: Hash, default: {} - -# Deprecated -attribute :credentials_user, kind_of: [String, NilClass], default: nil - -## internal methods - -def xml_path - "#{service_path}/#{manifest_type}" -end - -def xml_file - "#{xml_path}/#{name}.xml" -end - -require 'fileutils' -require 'digest/md5' - -# Save a checksum out to a file, for future chef runs -# -def save_checksum - Chef::Log.debug("Saving checksum for SMF #{name}: #{checksum}") - ::FileUtils.mkdir_p(Chef::Config.checksum_path) - f = ::File.new(checksum_file, 'w') - f.write checksum -end - -def remove_checksum - return unless ::File.exist?(checksum_file) - - Chef::Log.debug("Removing checksum for SMF #{name}") - ::File.delete(checksum_file) -end - -# Load current resource from checksum file and projects database. -# This should only ever be called on @current_resource, never on new_resource. -# -def load - @checksum ||= ::File.exist?(checksum_file) ? ::File.read(checksum_file) : '' - @smf_exists = shell_out("svcs #{fmri}").exitstatus == 0 - Chef::Log.debug("Loaded checksum for SMF #{name}: #{@checksum}") - Chef::Log.debug("SMF service already exists for #{fmri}? #{@smf_exists.inspect}") -end - -def authorization_name - authorization || name -end - -def checksum - attributes = [ - user, credentials_user, group, - project, start_command, start_timeout, stop_command, - stop_timeout, restart_command, restart_timeout, - refresh_command, refresh_timeout, working_directory, - locale, authorization, manifest_type, service_path, - duration, ignore.to_s, include_default_dependencies, - dependencies, fmri, stability, environment_as_string, - privilege_list, property_groups_as_string, '0' - ] - @checksum ||= Digest::MD5.hexdigest(attributes.join(':')) -end - -def checksum_file - "#{Chef::Config.checksum_path}/smf--#{name}" -end - -def environment_as_string - return nil if environment.nil? - environment.inject('') { |memo, k, v| memo << [k, v].join('|') } -end - -def privilege_list - privileges.join(',') -end - -def property_groups_as_string - return nil if property_groups.empty? - property_groups.inject('') { |memo, k, v| memo << [k, v].join('|') } -end - -def smf_exists? - !!@smf_exists -end diff --git a/cookbooks/smf/templates/default/SMFServicesOK.sh.erb b/cookbooks/smf/templates/default/SMFServicesOK.sh.erb deleted file mode 100644 index b135216..0000000 --- a/cookbooks/smf/templates/default/SMFServicesOK.sh.erb +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -# if we're on SunOS 5.10+, we should check for beat services. - -if [ "`uname -s`" = "SunOS" ] && [ `uname -r|cut -d. -f1` -ge 5 ] && [ `uname -r|cut -d. -f2` -ge 10 ] -then - B=`svcs -Ha |egrep -v "disabled|online|legacy_run"` - if [ "foo$B" == "foo" ] - then - echo "OK" - else - echo $B - fi -fi diff --git a/cookbooks/smf/templates/default/SMFServicesOK.snmpd.conf.erb b/cookbooks/smf/templates/default/SMFServicesOK.snmpd.conf.erb deleted file mode 100644 index 8d3add8..0000000 --- a/cookbooks/smf/templates/default/SMFServicesOK.snmpd.conf.erb +++ /dev/null @@ -1 +0,0 @@ -extend SMFServicesOK /opt/scripts/SMFServicesOK.sh diff --git a/cookbooks/unattended-upgrades/CHANGELOG.md b/cookbooks/unattended-upgrades/CHANGELOG.md deleted file mode 100644 index ff191d0..0000000 --- a/cookbooks/unattended-upgrades/CHANGELOG.md +++ /dev/null @@ -1,22 +0,0 @@ -unattended-upgrades -=================== - -v0.1.2 (2014-07-01) -------------------- - -Fixes - -* Fixed missing auto-upgrades.conf, preventing cron triggering these upgrades - -Changes - -* no longer installs mailutils - a warning will be emitted if a mailer can't be detected instead - -Features - -* Now with unit and integration tests - - -v0.1.0 (2014-05-08) -------------------- -- First officially published release. Ubuntu support tested on 12.04 diff --git a/cookbooks/unattended-upgrades/README.md b/cookbooks/unattended-upgrades/README.md deleted file mode 100644 index 783de80..0000000 --- a/cookbooks/unattended-upgrades/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# unattended-upgrades cookbook - -This cookbook configures the unattended-upgrades package which performs automatic package updates on debian systems. - -Build status: - -[![Build Status](https://travis-ci.org/jeremyolliver/cookbook-unattended-upgrades.png?branch=master)](https://travis-ci.org/jeremyolliver/cookbook-unattended-upgrades) - -CI automatically runs linting and unit tests. You may also run more thorough integration tests via Vagrant as well. See below for details on how to do that. - -# Requirements - -Debian or Ubuntu Operating System and the `apt` cookbook - -# Usage - -Simply include the cookbook "unattended-upgrades". Common config that you may want to change: - -`node['unattended-upgrades']['admin_email']` Defaults to `'root@localhost'` Set to nil to disable email notification, or any other external email - -`node['unattended-upgrades']['allowed_origins']` - -Default value (at default precedence) is: - - { - 'security' => true, - 'updates' => false, - 'proposed' => false, - 'backports' => false - } - -You can change this to enable non-critical updates by setting in a role or environment: - - "default_attributes": { - "unattended-upgrades": { - "allowed_origins": { - "updates": true - } - } - } - -Please note that if you set your own changes at an `override` precedence, then the two hashes will not be merged together, and the full list should be specified again. e.g. alternately: - - "override_attributes": { - "unattended-upgrades": { - "allowed_origins": { - "security": true, - "updates": true, - "proposed": false, - "backports": false - } - } - } - -TODO: Third party PPA's are not yet supported in the allowed origins section - -`node['unattended-upgrades']['mail_only_on_error']` Set this to `true` if you want to skip mails for successful updates, however it can be helpful for troubleshooting to have a record of when packages were updated if you need to correlate when an error started occurring with the time packages were updated. - -`node['unattended-upgrades']['minimal_steps']` Set this to `true` if you expect to be able to reboot the server with minimal interruption and the updates might be running at the time. With this left on the default value of false, the server will wait for all updates to complete before shutting down. See the full attributes list and the comments in the template file for more information. This cookbook has strived to provide configurable attributes for as many options as possible to allow maximum flexibility. - -# Attributes - -* `['unattended-upgrades']['admin_email']` -* `['unattended-upgrades']['package_blacklist']` -* `['unattended-upgrades']['autofix_dpkg']` -* `['unattended-upgrades']['minimal_steps']` -* `['unattended-upgrades']['install_on_shutdown']` -* `['unattended-upgrades']['mail_only_on_error']` -* `['unattended-upgrades']['remove_unused_dependencies']` -* `['unattended-upgrades']['automatic_reboot']` -* `['unattended-upgrades']['download_limit']` -* `['unattended_upgrades']['update_package_lists_interval']` -* `['unattended_upgrades']['upgrade_interval']` -* `['unattended_upgrades']['download_upgradeable_interval']` -* `['unattended_upgrades']['autoclean_interval']` - -# Recipes - -`unattended-upgrades::default` - -# Cookbook Development - -Running the tests for this cookbook involves: - -Requires: -* ruby 1.9.2+ -* bundler (`gem install bundler` and `bundle install`) -* Vagrant 1.2+ (and Virtualbox) -* `vagrant plugin install vagrant-berkshelf` - -Run the lint tests via: `bundle exec rake style`. Run the full integration tests via: `bundle exec kitchen converge all` and `bundle exec kitchen verify all`. To remove the VM's `bundle exec kitchen destroy all` - -# Author - -Author:: Jeremy Olliver () diff --git a/cookbooks/unattended-upgrades/attributes/default.rb b/cookbooks/unattended-upgrades/attributes/default.rb deleted file mode 100644 index 0120756..0000000 --- a/cookbooks/unattended-upgrades/attributes/default.rb +++ /dev/null @@ -1,24 +0,0 @@ -default['unattended-upgrades']['admin_email'] = 'root@localhost' # Set to nil to disable, or override to another value -default['unattended-upgrades']['package_blacklist'] = [] -default['unattended-upgrades']['autofix_dpkg'] = true # Strongly advised not to change -default['unattended-upgrades']['minimal_steps'] = false # Set to true to split upgrade into steps making it easier to interrupt -default['unattended-upgrades']['install_on_shutdown'] = false -default['unattended-upgrades']['mail_only_on_error'] = false -default['unattended-upgrades']['remove_unused_dependencies'] = false -default['unattended-upgrades']['automatic_reboot'] = false -default['unattended-upgrades']['download_limit'] = nil # Set to Integer representing kb/sec limit - -default['unattended-upgrades']['allowed_origins'] = { - 'security' => true, - 'updates' => false, - 'proposed' => false, - 'backports' => false -} - -default['unattended-upgrades']['apt_recipe'] = 'default' - -# interval settings in days -default['unattended-upgrades']['update_package_lists_interval'] = 1 -default['unattended-upgrades']['upgrade_interval'] = 1 # In order for unattended upgrades to run at all, this must be set to an integer greater than or equal to 1 -default['unattended-upgrades']['download_upgradeable_interval'] = nil -default['unattended-upgrades']['autoclean_interval'] = nil diff --git a/cookbooks/unattended-upgrades/files/default/test/default_test.rb b/cookbooks/unattended-upgrades/files/default/test/default_test.rb deleted file mode 100644 index c5cf68c2..0000000 --- a/cookbooks/unattended-upgrades/files/default/test/default_test.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path('../support/helpers', __FILE__) - -describe_recipe 'unattended-upgrades::default' do - - include Helpers::Unattended_upgrades - - describe 'packages' do - it 'installs unattended-upgrades' do - package("unattended-upgrades").must_be_installed - end - end - - describe 'files' do - let(:config) { file("/etc/apt/apt.conf.d/50unattended-upgrades") } - let(:autoconfig) { file("/etc/apt/apt.conf.d/20auto-upgrades") } - - it 'should have correct file permissions' do - config.must_have(:mode, "644") - autoconfig.must_have(:mode, "644") - end - it 'should have correct owner' do - config.must_have(:owner, "root") - autoconfig.must_have(:owner, "root") - end - it 'should have correct group' do - config.must_have(:group, "root") - autoconfig.must_have(:group, "root") - end - - it 'should contain the correct config' do - config.must_include "Unattended-Upgrade::Mail \"#{node['unattended-upgrades']['admin_email']}\";" - end - - it 'should contain the security updates origin' do - # Although this test may fail on a setup with minitest-handler running on a live server - security updates really shouldn't be turned off - config.must_include '"${distro_id}:${distro_codename}-security";' - end - - it 'should run unattended upgrades according to the schedule' do - # Test might fail if unattended upgrades is disabled via run interval setting - but why run this test if the software is turned off? - autoconfig.must_include "APT::Periodic::Unattended-Upgrade \"#{node['unattended-upgrades']['upgrade_interval']}\";" - end - end - -end diff --git a/cookbooks/unattended-upgrades/files/default/test/support/helpers.rb b/cookbooks/unattended-upgrades/files/default/test/support/helpers.rb deleted file mode 100644 index aa8a189..0000000 --- a/cookbooks/unattended-upgrades/files/default/test/support/helpers.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'minitest/spec' - -module Helpers - module Unattended_upgrades - include MiniTest::Chef::Assertions - include MiniTest::Chef::Context - include MiniTest::Chef::Resources - end -end diff --git a/cookbooks/unattended-upgrades/metadata.json b/cookbooks/unattended-upgrades/metadata.json deleted file mode 100644 index 5464d7e..0000000 --- a/cookbooks/unattended-upgrades/metadata.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "unattended-upgrades", - "version": "0.1.2", - "description": "Installs/Configures unattended-upgrades", - "long_description": "# unattended-upgrades cookbook\n\nThis cookbook configures the unattended-upgrades package which performs automatic package updates on debian systems.\n\nBuild status:\n\n[![Build Status](https://travis-ci.org/jeremyolliver/cookbook-unattended-upgrades.png?branch=master)](https://travis-ci.org/jeremyolliver/cookbook-unattended-upgrades)\n\nCI automatically runs linting and unit tests. You may also run more thorough integration tests via Vagrant as well. See below for details on how to do that.\n\n# Requirements\n\nDebian or Ubuntu Operating System and the `apt` cookbook\n\n# Usage\n\nSimply include the cookbook \"unattended-upgrades\". Common config that you may want to change:\n\n`node['unattended-upgrades']['admin_email']` Defaults to `'root@localhost'` Set to nil to disable email notification, or any other external email\n\n`node['unattended-upgrades']['allowed_origins']`\n\nDefault value (at default precedence) is:\n\n {\n 'security' => true,\n 'updates' => false,\n 'proposed' => false,\n 'backports' => false\n }\n\nYou can change this to enable non-critical updates by setting in a role or environment:\n\n \"default_attributes\": {\n \"unattended-upgrades\": {\n \"allowed_origins\": {\n \"updates\": true\n }\n }\n }\n\nPlease note that if you set your own changes at an `override` precedence, then the two hashes will not be merged together, and the full list should be specified again. e.g. alternately:\n\n \"override_attributes\": {\n \"unattended-upgrades\": {\n \"allowed_origins\": {\n \"security\": true,\n \"updates\": true,\n \"proposed\": false,\n \"backports\": false\n }\n }\n }\n\nTODO: Third party PPA's are not yet supported in the allowed origins section\n\n`node['unattended-upgrades']['mail_only_on_error']` Set this to `true` if you want to skip mails for successful updates, however it can be helpful for troubleshooting to have a record of when packages were updated if you need to correlate when an error started occurring with the time packages were updated.\n\n`node['unattended-upgrades']['minimal_steps']` Set this to `true` if you expect to be able to reboot the server with minimal interruption and the updates might be running at the time. With this left on the default value of false, the server will wait for all updates to complete before shutting down. See the full attributes list and the comments in the template file for more information. This cookbook has strived to provide configurable attributes for as many options as possible to allow maximum flexibility.\n\n# Attributes\n\n* `['unattended-upgrades']['admin_email']`\n* `['unattended-upgrades']['package_blacklist']`\n* `['unattended-upgrades']['autofix_dpkg']`\n* `['unattended-upgrades']['minimal_steps']`\n* `['unattended-upgrades']['install_on_shutdown']`\n* `['unattended-upgrades']['mail_only_on_error']`\n* `['unattended-upgrades']['remove_unused_dependencies']`\n* `['unattended-upgrades']['automatic_reboot']`\n* `['unattended-upgrades']['download_limit']`\n* `['unattended_upgrades']['update_package_lists_interval']`\n* `['unattended_upgrades']['upgrade_interval']`\n* `['unattended_upgrades']['download_upgradeable_interval']`\n* `['unattended_upgrades']['autoclean_interval']`\n\n# Recipes\n\n`unattended-upgrades::default`\n\n# Cookbook Development\n\nRunning the tests for this cookbook involves:\n\nRequires:\n* ruby 1.9.2+\n* bundler (`gem install bundler` and `bundle install`)\n* Vagrant 1.2+ (and Virtualbox)\n* `vagrant plugin install vagrant-berkshelf`\n\nRun the lint tests via: `bundle exec rake style`. Run the full integration tests via: `bundle exec kitchen converge all` and `bundle exec kitchen verify all`. To remove the VM's `bundle exec kitchen destroy all`\n\n# Author\n\nAuthor:: Jeremy Olliver ()\n", - "maintainer": "Jeremy Olliver", - "maintainer_email": "jeremy.olliver@gmail.com", - "license": "Apache 2.0", - "platforms": { - "ubuntu": ">= 0.0.0" - }, - "dependencies": { - "apt": ">= 0.0.0" - }, - "recommendations": { - }, - "suggestions": { - }, - "conflicting": { - }, - "providing": { - "unattended-upgrades::default": ">= 0.0.0" - }, - "replacing": { - }, - "attributes": { - }, - "groupings": { - }, - "recipes": { - } -} \ No newline at end of file diff --git a/cookbooks/unattended-upgrades/metadata.rb b/cookbooks/unattended-upgrades/metadata.rb deleted file mode 100644 index 064ce32..0000000 --- a/cookbooks/unattended-upgrades/metadata.rb +++ /dev/null @@ -1,14 +0,0 @@ -name "unattended-upgrades" -maintainer "Jeremy Olliver" -maintainer_email "jeremy.olliver@gmail.com" -license "Apache 2.0" -description "Installs/Configures unattended-upgrades" -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version "0.1.2" - -# supports "debian" # Untested -supports "ubuntu" - -depends "apt" - -provides "unattended-upgrades::default" diff --git a/cookbooks/unattended-upgrades/recipes/default.rb b/cookbooks/unattended-upgrades/recipes/default.rb deleted file mode 100644 index daa551a..0000000 --- a/cookbooks/unattended-upgrades/recipes/default.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Cookbook Name:: unattended-upgrades -# Recipe:: default -# -# Copyright (C) 2013 Jeremy Olliver -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# include apt::default (or an alternate apt recipe) -include_recipe "apt::#{node['unattended-upgrades']['apt_recipe']}" - -package 'unattended-upgrades' - -# Stock systems should already have a compatible mail delivery mechanism (e.g. mailx binary) installed - warn if one is not detected -ruby_block 'warn-on-missing-mailer' do - block do - Chef::Log.warn("No mail package detected. If you want to be able to mail the output of unattended-upgrades, you should a package provides the `mailx` such as 'mailutils' or 'heirloom-mailx'") - end - not_if 'which mailx' -end - -template '/etc/apt/apt.conf.d/50unattended-upgrades' do - source 'unattended-upgrades.conf.erb' - owner 'root' - group 'root' - mode '0644' - variables( - :allowed_origins => node['unattended-upgrades']['allowed_origins'], - :package_blacklist => node['unattended-upgrades']['package_blacklist'], - :autofix_dpkg => node['unattended-upgrades']['autofix_dpkg'], - :minimal_steps => node['unattended-upgrades']['minimal_steps'], - :install_on_shutdown => node['unattended-upgrades']['install_on_shutdown'], - :admin_email => node['unattended-upgrades']['admin_email'], - :mail_only_on_error => node['unattended-upgrades']['mail_only_on_error'], - :remove_unused_dependencies => node['unattended-upgrades']['remove_unused_dependencies'], - :automatic_reboot => node['unattended-upgrades']['automatic_reboot'], - :download_limit => node['unattended-upgrades']['download_limit'] - ) -end - -template '/etc/apt/apt.conf.d/20auto-upgrades' do - source 'auto-upgrades.conf.erb' - owner 'root' - group 'root' - mode '0644' - variables( - :update_package_lists_interval => node['unattended-upgrades']['update_package_lists_interval'], - :upgrade_interval => node['unattended-upgrades']['upgrade_interval'], - :download_upgradeable_interval => node['unattended-upgrades']['download_upgradeable_interval'], - :autoclean_interval => node['unattended-upgrades']['autoclean_interval'], - ) -end diff --git a/cookbooks/unattended-upgrades/templates/default/auto-upgrades.conf.erb b/cookbooks/unattended-upgrades/templates/default/auto-upgrades.conf.erb deleted file mode 100644 index 57f8aa0..0000000 --- a/cookbooks/unattended-upgrades/templates/default/auto-upgrades.conf.erb +++ /dev/null @@ -1,4 +0,0 @@ -<% if @update_package_lists_interval -%>APT::Periodic::Update-Package-Lists "<%= @update_package_lists_interval %>";<% end -%> -<% if @upgrade_interval -%>APT::Periodic::Unattended-Upgrade "<%= @upgrade_interval %>";<% end -%> -<% if @download_upgradeable_interval -%>APT::Periodic::Download-Upgradeable-Packages "<%= @download_upgradeable_interval %>";<% end -%> -<% if @autoclean_interval -%>APT::Periodic::AutocleanInterval "<%= @autoclean_interval%>";<% end -%> diff --git a/cookbooks/unattended-upgrades/templates/default/unattended-upgrades.conf.erb b/cookbooks/unattended-upgrades/templates/default/unattended-upgrades.conf.erb deleted file mode 100644 index 09ff914..0000000 --- a/cookbooks/unattended-upgrades/templates/default/unattended-upgrades.conf.erb +++ /dev/null @@ -1,67 +0,0 @@ -// File configured by chef - don't edit manually - -// Automatically upgrade packages from these (origin:archive) pairs -Unattended-Upgrade::Allowed-Origins { -<% @allowed_origins.each do |origin, enabled| %> -<%= '//' unless enabled %> "${distro_id}:${distro_codename}-<%= origin %>"; -<% end %> -}; - -// List of packages to not update -Unattended-Upgrade::Package-Blacklist { -// "vim"; -// "libc6"; -// "libc6-dev"; -// "libc6-i686"; -<% @package_blacklist.each do |pkg| %> - "<%= pkg %>"; -<% end %> -}; - -// This option allows you to control if on a unclean dpkg exit -// unattended-upgrades will automatically run -// dpkg --force-confold --configure -a -// The default is true, to ensure updates keep getting installed -//Unattended-Upgrade::AutoFixInterruptedDpkg "false"; -Unattended-Upgrade::AutoFixInterruptedDpkg "<%= @autofix_dpkg %>"; - -// Split the upgrade into the smallest possible chunks so that -// they can be interrupted with SIGUSR1. This makes the upgrade -// a bit slower but it has the benefit that shutdown while a upgrade -// is running is possible (with a small delay) -//Unattended-Upgrade::MinimalSteps "true"; -Unattended-Upgrade::MinimalSteps "<%= @minimal_steps %>"; - -// Install all unattended-upgrades when the machine is shuting down -// instead of doing it in the background while the machine is running -// This will (obviously) make shutdown slower -//Unattended-Upgrade::InstallOnShutdown "true"; -Unattended-Upgrade::InstallOnShutdown "<%= @install_on_shutdown %>"; - -// Send email to this address for problems or packages upgrades -// If empty or unset then no email is sent, make sure that you -// have a working mail setup on your system. A package that provides -// 'mailx' must be installed. -//Unattended-Upgrade::Mail "root@localhost"; -<% if @admin_email %>Unattended-Upgrade::Mail "<%= @admin_email %>";<% end %> - -// Set this value to "true" to get emails only on errors. Default -// is to always send a mail if Unattended-Upgrade::Mail is set -//Unattended-Upgrade::MailOnlyOnError "true"; -Unattended-Upgrade::MailOnlyOnError "<%= @mail_only_on_error %>"; - -// Do automatic removal of new unused dependencies after the upgrade -// (equivalent to apt-get autoremove) -//Unattended-Upgrade::Remove-Unused-Dependencies "false"; -Unattended-Upgrade::Remove-Unused-Dependencies "<%= @remove_unused_dependencies %>"; - -// Automatically reboot *WITHOUT CONFIRMATION* if a -// the file /var/run/reboot-required is found after the upgrade -//Unattended-Upgrade::Automatic-Reboot "false"; -Unattended-Upgrade::Automatic-Reboot "<%= @automatic_reboot %>"; - - -// Use apt bandwidth limit feature, this example limits the download -// speed to 70kb/sec -//Acquire::http::Dl-Limit "70"; -<% if @download_limit %>Acquire::http::Dl-Limit "<%= @download_limit %>";<% end %> diff --git a/cookbooks/yum-epel/CHANGELOG.md b/cookbooks/yum-epel/CHANGELOG.md index 7c4b6ac..fcf4def 100644 --- a/cookbooks/yum-epel/CHANGELOG.md +++ b/cookbooks/yum-epel/CHANGELOG.md @@ -1,138 +1,42 @@ -# yum-epel Cookbook CHANGELOG - -This file is used to list changes made in each version of the yum-epel cookbook. - -## 2.1.1 (2017-01-05) - -- Revert how mirror list strings are generated to fix RHEL 7 - -## 2.1.0 (2016-12-22) - -- Test in Travis using the current build of chef/chef docker image -- Test on older Chef -- allow the use of any valid property via attributes -- fixing tests -- output versions in the job that is being ran -- cops - -## 2.0.0 (2016-11-26) - -- Clarify that we require Chef 12.1+ not 12.0+ -- Use compat_resource instead of the yum cookbook -- Add integration testing with inspec - -## 1.0.2 (2016-10-21) - -- Remove upper bound on yum constraint - -## 1.0.1 (2016-09-11) - -- Fix epel-testing attributes - -## 1.0.0 (2016-09-06) - -- Add chef_version metadata -- Testing updates -- Remove support for Chef 11 - -## v0.7.1 (2016-08-19) - -- Remove bats testing -- Fix attribute settings -- Cleanup travis file - -## v0.7.0 (2016-04-27) - -- Added support for IBM zlinux platform -- Added back the Test Kitchen support for local vagrant testing -- Added long_description to the metadata -- Loosen the dependency on the yum cookbook - -## v0.6.5 - -- updated to use `make_cache` option that yum cookbook allows for the yum resource to use. - -## v0.6.5 (2015-11-23) - -- Fix setting bool false properties - -## v0.6.4 (2015-10-27) - -- Updating default recipe for Chef 13 deprecation warnings. Not -- passing nil. - -## v0.6.3 (2015-09-22) - -- Added standard Chef gitignore and chefignore files -- Added the standard chef rubocop config -- Update contributing, maintainers, and testing docs -- Update Chefspec config to 4.X format -- Update distro versions in the Kitchen config -- Add Travis CI and cookbook version badges in the readme -- Expand the requirements section in the readme -- Add additional distros to the metadata -- Added source_url and issues_url metadata - -## v0.6.2 (2015-06-21) - -- Depending on yum ~> 3.2 -- Support for the password attribute wasn't added to the -- yum_repository LWRP until yum 3.2.0. - -## v0.6.1 (2015-06-21) - -- Switching to https for URL links -- Using metalink URLs - -## v0.6.0 (2015-01-03) - -- Adding EL7 support - -## v0.5.3 (2014-10-28) - -- Revert Use HTTPS for GPG keys and mirror lists - -## v0.5.2 (2014-10-28) - -- Use HTTPS for GPG keys and mirror lists -- Use local key on Amazon Linux - -## v0.5.0 (2014-09-02) - -- Add all attribute available to LWRP to allow for tuning. - -## v0.4.0 (2014-07-27) - -- [#9] Allowing list of repositories to reference configurable. - -## v0.3.6 (2014-04-09) +yum-epel Cookbook CHANGELOG +====================== +This file is used to list changes made in each version of the yum-centos cookbook. +v0.3.6 (2014-04-09) +------------------- - [COOK-4509] add RHEL7 support to yum-epel cookbook -## v0.3.4 (2014-02-19) +v0.3.4 (2014-02-19) +------------------- COOK-4353 - Fixing typo in readme -## v0.3.2 (2014-02-13) +v0.3.2 (2014-02-13) +------------------- Updating README to explain the 'managed' parameter -## v0.3.0 (2014-02-12) +v0.3.0 (2014-02-12) +------------------- [COOK-4292] - Do not manage secondary repos by default -## v0.2.0 +v0.2.0 +------ Adding Amazon Linux support -## v0.1.6 +v0.1.6 +------ Fixing up attribute values for EL6 -## v0.1.4 +v0.1.4 +------ Adding CHANGELOG.md -## v0.1.0 +v0.1.0 +------ initial release diff --git a/cookbooks/yum-epel/MAINTAINERS.md b/cookbooks/yum-epel/MAINTAINERS.md deleted file mode 100644 index 8412458..0000000 --- a/cookbooks/yum-epel/MAINTAINERS.md +++ /dev/null @@ -1,19 +0,0 @@ - - -# Maintainers -This file lists how this cookbook project is maintained. When making changes to the system, this -file tells you who needs to review your patch - you need a review from an existing maintainer -for the cookbook to provide a :+1: on your pull request. Additionally, you need -to not receive a veto from a Lieutenant or the Project Lead. - -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) -for details on the process and how to become a maintainer or the project lead. - -# Project Maintainer -* [Jennifer Davis](https://github.com/sigje) - -# Maintainers -* [Jennifer Davis](https://github.com/sigje) -* [Sean OMeara](https://github.com/someara) -* [Tim Smith](https://github.com/tas50) -* [Thom May](https://github.com/thommay) diff --git a/cookbooks/yum-epel/README.md b/cookbooks/yum-epel/README.md index a4d41ad..c4550f3 100644 --- a/cookbooks/yum-epel/README.md +++ b/cookbooks/yum-epel/README.md @@ -1,41 +1,21 @@ -# yum-epel Cookbook +yum-epel Cookbook +============ -[![Build Status](https://travis-ci.org/chef-cookbooks/yum-epel.svg?branch=master)](http://travis-ci.org/chef-cookbooks/yum-epel) [![Cookbook Version](https://img.shields.io/cookbook/v/yum-epel.svg)](https://supermarket.chef.io/cookbooks/yum-epel) +The yum-epel cookbook takes over management of the default +repositoryids shipped with epel-release. It allows attribute +manipulation of `epel`, `epel-debuginfo`, `epel-source`, `epel-testing`, +`epel-testing-debuginfo`, and `epel-testing-source`. -Extra Packages for Enterprise Linux (or EPEL) is a Fedora Special Interest Group that creates, maintains, and manages a high quality set of additional packages for Enterprise Linux, including, but not limited to, Red Hat Enterprise Linux (RHEL), CentOS and Scientific Linux (SL), Oracle Linux (OL). - -The yum-epel cookbook takes over management of the default repositoryids shipped with epel-release. It allows attribute manipulation of `epel`, `epel-debuginfo`, `epel-source`, `epel-testing`, `epel-testing-debuginfo`, and `epel-testing-source`. - -## Requirements - -### Platforms - -- RHEL/CentOS and derivatives - -### Chef - -- Chef 12.1+ - -### Cookbooks - -- compat_resource - -## Attributes +Requirements +------------ +* Chef 11 or higher +* yum cookbook version 3.0.0 or higher +Attributes +---------- The following attributes are set by default -```ruby -default['yum-epel']['repos'] = %w( - epel - epel-debuginfo - epel-source - epel-testing - epel-testing-debuginfo - epel-testing-source -) -``` - -```ruby +``` ruby default['yum']['epel']['repositoryid'] = 'epel' default['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' default['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch' @@ -46,7 +26,7 @@ default['yum']['epel']['enabled'] = true default['yum']['epel']['managed'] = true ``` -```ruby +``` ruby default['yum']['epel-debuginfo']['repositoryid'] = 'epel-debuginfo' default['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Debug' default['yum']['epel-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch' @@ -57,7 +37,7 @@ default['yum']['epel-debuginfo']['enabled'] = false default['yum']['epel-debuginfo']['managed'] = false ``` -```ruby +``` ruby default['yum']['epel-source']['repositoryid'] = 'epel-source' default['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Source' default['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-6&arch=$basearch' @@ -68,7 +48,7 @@ default['yum']['epel-source']['enabled'] = false default['yum']['epel-source']['managed'] = false ``` -```ruby +``` ruby default['yum']['epel-testing']['repositoryid'] = 'epel-testing' default['yum']['epel-testing']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch' default['yum']['epel-testing']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-epel6&arch=$basearch' @@ -79,7 +59,7 @@ default['yum']['epel-testing']['enabled'] = false default['yum']['epel-testing']['managed'] = false ``` -```ruby +``` ruby default['yum']['epel-testing-debuginfo']['repositoryid'] = 'epel-testing-debuginfo' default['yum']['epel-testing-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Debug' default['yum']['epel-testing-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel6&arch=$basearch' @@ -90,7 +70,7 @@ default['yum']['epel-testing-debuginfo']['enabled'] = false default['yum']['epel-testing-debuginfo']['managed'] = false ``` -```ruby +``` ruby default['yum']['epel-testing-source']['repositoryid'] = 'epel-testing-source' default['yum']['epel-testing-source']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Source' default['yum']['epel-testing-source']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel6&arch=$basearch' @@ -101,10 +81,11 @@ default['yum']['epel-testing-source']['enabled'] = false default['yum']['epel-testing-source']['managed'] = false ``` -## Recipes -- default - Walks through node attributes and feeds a yum_resource -- parameters. The following is an example a resource generated by the -- recipe during compilation. +Recipes +------- +* default - Walks through node attributes and feeds a yum_resource + parameters. The following is an example a resource generated by the + recipe during compilation. ```ruby yum_repository 'epel' do @@ -116,7 +97,8 @@ default['yum']['epel-testing-source']['managed'] = false end ``` -## Usage Example +Usage Example +------------- To disable the epel repository through a Role or Environment definition ``` @@ -131,18 +113,22 @@ default_attributes( ) ``` -Uncommonly used repositoryids are not managed by default. This is speeds up integration testing pipelines by avoiding yum-cache builds that nobody cares about. To enable the epel-testing repository with a wrapper cookbook, place the following in a recipe: +Uncommonly used repositoryids are not managed by default. This is +speeds up integration testing pipelines by avoiding yum-cache builds +that nobody cares about. To enable the epel-testing repository with a +wrapper cookbook, place the following in a recipe: -```ruby +``` node.default['yum']['epel-testing']['enabled'] = true node.default['yum']['epel-testing']['managed'] = true include_recipe 'yum-epel' ``` -## More Examples +More Examples +------------- Point the epel repositories at an internally hosted server. -```ruby +``` node.default['yum']['epel']['enabled'] = true node.default['yum']['epel']['mirrorlist'] = nil node.default['yum']['epel']['baseurl'] = 'https://internal.example.com/centos/6/os/x86_64' @@ -151,13 +137,13 @@ node.default['yum']['epel']['sslverify'] = false include_recipe 'yum-epel' ``` -## License & Authors +License & Authors +----------------- +- Author:: Sean OMeara () -**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io)) +```text +Copyright:: 2011-2013 Opscode, Inc. -**Copyright:** 2011-2016, Chef Software, Inc. - -``` Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/cookbooks/yum-epel/attributes/default.rb b/cookbooks/yum-epel/attributes/default.rb deleted file mode 100644 index 960a280..0000000 --- a/cookbooks/yum-epel/attributes/default.rb +++ /dev/null @@ -1,8 +0,0 @@ -default['yum-epel']['repos'] = %w( - epel - epel-debuginfo - epel-source - epel-testing - epel-testing-debuginfo - epel-testing-source -) diff --git a/cookbooks/yum-epel/attributes/epel-debuginfo.rb b/cookbooks/yum-epel/attributes/epel-debuginfo.rb index b1142e5..0e72757 100644 --- a/cookbooks/yum-epel/attributes/epel-debuginfo.rb +++ b/cookbooks/yum-epel/attributes/epel-debuginfo.rb @@ -1,15 +1,28 @@ default['yum']['epel-debuginfo']['repositoryid'] = 'epel-debuginfo' -default['yum']['epel-debuginfo']['description'] = "Extra Packages for #{node['platform_version'].to_i} - $basearch - Debug" + case node['platform'] when 'amazon' - default['yum']['epel-debuginfo']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-6&arch=$basearch' + default['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' + default['yum']['epel-debuginfo']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' default['yum']['epel-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' else - default['yum']['epel-debuginfo']['mirrorlist'] = "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-#{node['platform_version'].to_i}&arch=$basearch" - default['yum']['epel-debuginfo']['gpgkey'] = "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}" + case node['platform_version'].to_i + when 5 + default['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 5 - $basearch - Debug' + default['yum']['epel-debuginfo']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-5&arch=$basearch' + default['yum']['epel-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL' + when 6 + default['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Debug' + default['yum']['epel-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch' + default['yum']['epel-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' + when 7 + default['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 7 - $basearch - Debug' + default['yum']['epel-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch' + default['yum']['epel-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7' + end end + default['yum']['epel-debuginfo']['failovermethod'] = 'priority' default['yum']['epel-debuginfo']['gpgcheck'] = true default['yum']['epel-debuginfo']['enabled'] = false default['yum']['epel-debuginfo']['managed'] = false -default['yum']['epel-debuginfo']['make_cache'] = true diff --git a/cookbooks/yum-epel/attributes/epel-source.rb b/cookbooks/yum-epel/attributes/epel-source.rb index 11ef8e4..1433eed 100644 --- a/cookbooks/yum-epel/attributes/epel-source.rb +++ b/cookbooks/yum-epel/attributes/epel-source.rb @@ -1,15 +1,28 @@ default['yum']['epel-source']['repositoryid'] = 'epel-source' -default['yum']['epel-source']['description'] = "Extra Packages for #{node['platform_version'].to_i} - $basearch - Source" + case node['platform'] when 'amazon' - default['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-6&arch=$basearch' + default['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' + default['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' default['yum']['epel-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' else - default['yum']['epel-source']['mirrorlist'] = "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-#{node['platform_version'].to_i}&arch=$basearch" - default['yum']['epel-source']['gpgkey'] = "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}" + case node['platform_version'].to_i + when 5 + default['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 5 - $basearch - Source' + default['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-5&arch=$basearch' + default['yum']['epel-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL' + when 6 + default['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Source' + default['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-6&arch=$basearch' + default['yum']['epel-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' + when 7 + default['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 7 - $basearch - Source' + default['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-7&arch=$basearch' + default['yum']['epel-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7' + end end + default['yum']['epel-source']['failovermethod'] = 'priority' default['yum']['epel-source']['gpgcheck'] = true default['yum']['epel-source']['enabled'] = false default['yum']['epel-source']['managed'] = false -default['yum']['epel-source']['make_cache'] = true diff --git a/cookbooks/yum-epel/attributes/epel-testing-debuginfo.rb b/cookbooks/yum-epel/attributes/epel-testing-debuginfo.rb index 54e9b9b..14353dc 100644 --- a/cookbooks/yum-epel/attributes/epel-testing-debuginfo.rb +++ b/cookbooks/yum-epel/attributes/epel-testing-debuginfo.rb @@ -1,15 +1,24 @@ default['yum']['epel-testing-debuginfo']['repositoryid'] = 'epel-testing-debuginfo' -default['yum']['epel-testing-debuginfo']['description'] = "Extra Packages for #{node['platform_version'].to_i} - $basearch - Testing Debug" + case node['platform'] when 'amazon' - default['yum']['epel-testing-debuginfo']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=testing-debug-epel6&arch=$basearch' + default['yum']['epel-testing-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' + default['yum']['epel-testing-debuginfo']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' default['yum']['epel-testing-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' else - default['yum']['epel-testing-debuginfo']['mirrorlist'] = "http://mirrors.fedoraproject.org/mirrorlist?repo=testing-debug-epel#{node['platform_version'].to_i}&arch=$basearch" - default['yum']['epel-testing-debuginfo']['gpgkey'] = "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}" + case node['platform_version'].to_i + when 5 + default['yum']['epel-testing-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 5 - Testing - $basearch Debug' + default['yum']['epel-testing-debuginfo']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=testing-debug-epel5&arch=$basearch' + default['yum']['epel-testing-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL' + when 6 + default['yum']['epel-testing-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Debug' + default['yum']['epel-testing-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel6&arch=$basearch' + default['yum']['epel-testing-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' + end end + default['yum']['epel-testing-debuginfo']['failovermethod'] = 'priority' default['yum']['epel-testing-debuginfo']['gpgcheck'] = true default['yum']['epel-testing-debuginfo']['enabled'] = false default['yum']['epel-testing-debuginfo']['managed'] = false -default['yum']['epel-testing-debuginfo']['make_cache'] = true diff --git a/cookbooks/yum-epel/attributes/epel-testing-source.rb b/cookbooks/yum-epel/attributes/epel-testing-source.rb index f92031b..7f82192 100644 --- a/cookbooks/yum-epel/attributes/epel-testing-source.rb +++ b/cookbooks/yum-epel/attributes/epel-testing-source.rb @@ -1,15 +1,24 @@ default['yum']['epel-testing-source']['repositoryid'] = 'epel-testing-source' -default['yum']['epel-testing-source']['description'] = "Extra Packages for #{node['platform_version'].to_i} - $basearch - Testing Source" + case node['platform'] when 'amazon' - default['yum']['epel-testing-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=testing-source-epel6&arch=$basearch' + default['yum']['epel-testing-source']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' + default['yum']['epel-testing-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' default['yum']['epel-testing-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' else - default['yum']['epel-testing-source']['mirrorlist'] = "http://mirrors.fedoraproject.org/mirrorlist?repo=testing-source-epel#{node['platform_version'].to_i}&arch=$basearch" - default['yum']['epel-testing-source']['gpgkey'] = "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}" + case node['platform_version'].to_i + when 5 + default['yum']['epel-testing-source']['description'] = 'Extra Packages for Enterprise Linux 5 - Testing - $basearch Source' + default['yum']['epel-testing-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=testing-source-epel5&arch=$basearch' + default['yum']['epel-testing-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL' + when 6 + default['yum']['epel-testing-source']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Source' + default['yum']['epel-testing-source']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel6&arch=$basearch' + default['yum']['epel-testing-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' + end end + default['yum']['epel-testing-source']['failovermethod'] = 'priority' default['yum']['epel-testing-source']['gpgcheck'] = true default['yum']['epel-testing-source']['enabled'] = false default['yum']['epel-testing-source']['managed'] = false -default['yum']['epel-testing-source']['make_cache'] = true diff --git a/cookbooks/yum-epel/attributes/epel-testing.rb b/cookbooks/yum-epel/attributes/epel-testing.rb index ee9d496..d54a0f1 100644 --- a/cookbooks/yum-epel/attributes/epel-testing.rb +++ b/cookbooks/yum-epel/attributes/epel-testing.rb @@ -1,15 +1,24 @@ default['yum']['epel-testing']['repositoryid'] = 'epel-testing' -default['yum']['epel-testing']['description'] = "Extra Packages for #{node['platform_version'].to_i} - $basearch - Testing " + case node['platform'] when 'amazon' - default['yum']['epel-testing']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=testing-epel6&arch=$basearch' + default['yum']['epel-testing']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' + default['yum']['epel-testing']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' default['yum']['epel-testing']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' else - default['yum']['epel-testing']['mirrorlist'] = "http://mirrors.fedoraproject.org/mirrorlist?repo=testing-epel#{node['platform_version'].to_i}&arch=$basearch" - default['yum']['epel-testing']['gpgkey'] = "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}" + case node['platform_version'].to_i + when 5 + default['yum']['epel-testing']['description'] = 'Extra Packages for Enterprise Linux 5 - Testing - $basearch' + default['yum']['epel-testing']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=testing-epel5&arch=$basearch' + default['yum']['epel-testing']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL' + when 6 + default['yum']['epel-testing']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch' + default['yum']['epel-testing']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-epel6&arch=$basearch' + default['yum']['epel-testing']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' + end end + default['yum']['epel-testing']['failovermethod'] = 'priority' default['yum']['epel-testing']['gpgcheck'] = true default['yum']['epel-testing']['enabled'] = false default['yum']['epel-testing']['managed'] = false -default['yum']['epel-testing']['make_cache'] = true diff --git a/cookbooks/yum-epel/attributes/epel.rb b/cookbooks/yum-epel/attributes/epel.rb index ab17be5..07dceb6 100644 --- a/cookbooks/yum-epel/attributes/epel.rb +++ b/cookbooks/yum-epel/attributes/epel.rb @@ -1,21 +1,28 @@ default['yum']['epel']['repositoryid'] = 'epel' -default['yum']['epel']['description'] = "Extra Packages for #{node['platform_version'].to_i} - $basearch" -case node['kernel']['machine'] -when 's390x' - default['yum']['epel']['baseurl'] = 'https://kojipkgs.fedoraproject.org/rhel/rc/7/Server/s390x/os/' - default['yum']['epel']['gpgkey'] = 'https://kojipkgs.fedoraproject.org/rhel/rc/7/Server/s390x/os/RPM-GPG-KEY-redhat-release' + +case node['platform'] +when 'amazon' + default['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' + default['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' + default['yum']['epel']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' else - case node['platform'] - when 'amazon' + case node['platform_version'].to_i + when 5 + default['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 5 - $basearch' + default['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch' + default['yum']['epel']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL' + when 6 + default['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch' default['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch' default['yum']['epel']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6' - else - default['yum']['epel']['mirrorlist'] = "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-#{node['platform_version'].to_i}&arch=$basearch" - default['yum']['epel']['gpgkey'] = "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node['platform_version'].to_i}" + when 7 + default['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 7 - $basearch' + default['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-7&arch=$basearch' + default['yum']['epel']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7' end end + default['yum']['epel']['failovermethod'] = 'priority' default['yum']['epel']['gpgcheck'] = true default['yum']['epel']['enabled'] = true default['yum']['epel']['managed'] = true -default['yum']['epel']['make_cache'] = true diff --git a/cookbooks/yum-epel/metadata.json b/cookbooks/yum-epel/metadata.json index 2f8805e..f50f5c0 100644 --- a/cookbooks/yum-epel/metadata.json +++ b/cookbooks/yum-epel/metadata.json @@ -1 +1,30 @@ -{"name":"yum-epel","version":"2.1.1","description":"Installs and configures the EPEL Yum repository","long_description":"# yum-epel Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/yum-epel.svg?branch=master)](http://travis-ci.org/chef-cookbooks/yum-epel) [![Cookbook Version](https://img.shields.io/cookbook/v/yum-epel.svg)](https://supermarket.chef.io/cookbooks/yum-epel)\n\nExtra Packages for Enterprise Linux (or EPEL) is a Fedora Special Interest Group that creates, maintains, and manages a high quality set of additional packages for Enterprise Linux, including, but not limited to, Red Hat Enterprise Linux (RHEL), CentOS and Scientific Linux (SL), Oracle Linux (OL).\n\nThe yum-epel cookbook takes over management of the default repositoryids shipped with epel-release. It allows attribute manipulation of `epel`, `epel-debuginfo`, `epel-source`, `epel-testing`, `epel-testing-debuginfo`, and `epel-testing-source`.\n\n## Requirements\n\n### Platforms\n\n- RHEL/CentOS and derivatives\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- compat_resource\n\n## Attributes\n\nThe following attributes are set by default\n\n```ruby\ndefault['yum-epel']['repos'] = %w(\n epel\n epel-debuginfo\n epel-source\n epel-testing\n epel-testing-debuginfo\n epel-testing-source\n)\n```\n\n```ruby\ndefault['yum']['epel']['repositoryid'] = 'epel'\ndefault['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch'\ndefault['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch'\ndefault['yum']['epel']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel']['failovermethod'] = 'priority'\ndefault['yum']['epel']['gpgcheck'] = true\ndefault['yum']['epel']['enabled'] = true\ndefault['yum']['epel']['managed'] = true\n```\n\n```ruby\ndefault['yum']['epel-debuginfo']['repositoryid'] = 'epel-debuginfo'\ndefault['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Debug'\ndefault['yum']['epel-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch'\ndefault['yum']['epel-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-debuginfo']['failovermethod'] = 'priority'\ndefault['yum']['epel-debuginfo']['gpgcheck'] = true\ndefault['yum']['epel-debuginfo']['enabled'] = false\ndefault['yum']['epel-debuginfo']['managed'] = false\n```\n\n```ruby\ndefault['yum']['epel-source']['repositoryid'] = 'epel-source'\ndefault['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Source'\ndefault['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-6&arch=$basearch'\ndefault['yum']['epel-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-source']['failovermethod'] = 'priority'\ndefault['yum']['epel-source']['gpgcheck'] = true\ndefault['yum']['epel-source']['enabled'] = false\ndefault['yum']['epel-source']['managed'] = false\n```\n\n```ruby\ndefault['yum']['epel-testing']['repositoryid'] = 'epel-testing'\ndefault['yum']['epel-testing']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch'\ndefault['yum']['epel-testing']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-epel6&arch=$basearch'\ndefault['yum']['epel-testing']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6r'\ndefault['yum']['epel-testing']['failovermethod'] = 'priority'\ndefault['yum']['epel-testing']['gpgcheck'] = true\ndefault['yum']['epel-testing']['enabled'] = false\ndefault['yum']['epel-testing']['managed'] = false\n```\n\n```ruby\ndefault['yum']['epel-testing-debuginfo']['repositoryid'] = 'epel-testing-debuginfo'\ndefault['yum']['epel-testing-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Debug'\ndefault['yum']['epel-testing-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel6&arch=$basearch'\ndefault['yum']['epel-testing-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-testing-debuginfo']['failovermethod'] = 'priority'\ndefault['yum']['epel-testing-debuginfo']['gpgcheck'] = true\ndefault['yum']['epel-testing-debuginfo']['enabled'] = false\ndefault['yum']['epel-testing-debuginfo']['managed'] = false\n```\n\n```ruby\ndefault['yum']['epel-testing-source']['repositoryid'] = 'epel-testing-source'\ndefault['yum']['epel-testing-source']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Source'\ndefault['yum']['epel-testing-source']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel6&arch=$basearch'\ndefault['yum']['epel-testing-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-testing-source']['failovermethod'] = 'priority'\ndefault['yum']['epel-testing-source']['gpgcheck'] = true\ndefault['yum']['epel-testing-source']['enabled'] = false\ndefault['yum']['epel-testing-source']['managed'] = false\n```\n\n## Recipes\n- default - Walks through node attributes and feeds a yum_resource\n- parameters. The following is an example a resource generated by the\n- recipe during compilation.\n\n```ruby\n yum_repository 'epel' do\n mirrorlist 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch'\n description 'Extra Packages for Enterprise Linux 5 - $basearch'\n enabled true\n gpgcheck true\n gpgkey 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL'\n end\n```\n\n## Usage Example\nTo disable the epel repository through a Role or Environment definition\n\n```\ndefault_attributes(\n :yum => {\n :epel => {\n :enabled => {\n false\n }\n }\n }\n )\n```\n\nUncommonly used repositoryids are not managed by default. This is speeds up integration testing pipelines by avoiding yum-cache builds that nobody cares about. To enable the epel-testing repository with a wrapper cookbook, place the following in a recipe:\n\n```ruby\nnode.default['yum']['epel-testing']['enabled'] = true\nnode.default['yum']['epel-testing']['managed'] = true\ninclude_recipe 'yum-epel'\n```\n\n## More Examples\nPoint the epel repositories at an internally hosted server.\n\n```ruby\nnode.default['yum']['epel']['enabled'] = true\nnode.default['yum']['epel']['mirrorlist'] = nil\nnode.default['yum']['epel']['baseurl'] = 'https://internal.example.com/centos/6/os/x86_64'\nnode.default['yum']['epel']['sslverify'] = false\n\ninclude_recipe 'yum-epel'\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2011-2016, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","zlinux":">= 0.0.0"},"dependencies":{"compat_resource":">= 12.16.3"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file +{ + "name": "yum-epel", + "version": "0.3.6", + "description": "Installs/Configures yum-epel", + "long_description": "yum-epel Cookbook\n============\n\nThe yum-epel cookbook takes over management of the default\nrepositoryids shipped with epel-release. It allows attribute\nmanipulation of `epel`, `epel-debuginfo`, `epel-source`, `epel-testing`,\n`epel-testing-debuginfo`, and `epel-testing-source`.\n\nRequirements\n------------\n* Chef 11 or higher\n* yum cookbook version 3.0.0 or higher\n\nAttributes\n----------\nThe following attributes are set by default\n\n``` ruby\ndefault['yum']['epel']['repositoryid'] = 'epel'\ndefault['yum']['epel']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch'\ndefault['yum']['epel']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch'\ndefault['yum']['epel']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel']['failovermethod'] = 'priority'\ndefault['yum']['epel']['gpgcheck'] = true\ndefault['yum']['epel']['enabled'] = true\ndefault['yum']['epel']['managed'] = true\n```\n\n``` ruby\ndefault['yum']['epel-debuginfo']['repositoryid'] = 'epel-debuginfo'\ndefault['yum']['epel-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Debug'\ndefault['yum']['epel-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch'\ndefault['yum']['epel-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-debuginfo']['failovermethod'] = 'priority'\ndefault['yum']['epel-debuginfo']['gpgcheck'] = true\ndefault['yum']['epel-debuginfo']['enabled'] = false\ndefault['yum']['epel-debuginfo']['managed'] = false\n```\n\n``` ruby\ndefault['yum']['epel-source']['repositoryid'] = 'epel-source'\ndefault['yum']['epel-source']['description'] = 'Extra Packages for Enterprise Linux 6 - $basearch - Source'\ndefault['yum']['epel-source']['mirrorlist'] = 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-6&arch=$basearch'\ndefault['yum']['epel-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-source']['failovermethod'] = 'priority'\ndefault['yum']['epel-source']['gpgcheck'] = true\ndefault['yum']['epel-source']['enabled'] = false\ndefault['yum']['epel-source']['managed'] = false\n```\n\n``` ruby\ndefault['yum']['epel-testing']['repositoryid'] = 'epel-testing'\ndefault['yum']['epel-testing']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch'\ndefault['yum']['epel-testing']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-epel6&arch=$basearch'\ndefault['yum']['epel-testing']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6r'\ndefault['yum']['epel-testing']['failovermethod'] = 'priority'\ndefault['yum']['epel-testing']['gpgcheck'] = true\ndefault['yum']['epel-testing']['enabled'] = false\ndefault['yum']['epel-testing']['managed'] = false\n```\n\n``` ruby\ndefault['yum']['epel-testing-debuginfo']['repositoryid'] = 'epel-testing-debuginfo'\ndefault['yum']['epel-testing-debuginfo']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Debug'\ndefault['yum']['epel-testing-debuginfo']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-debug-epel6&arch=$basearch'\ndefault['yum']['epel-testing-debuginfo']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-testing-debuginfo']['failovermethod'] = 'priority'\ndefault['yum']['epel-testing-debuginfo']['gpgcheck'] = true\ndefault['yum']['epel-testing-debuginfo']['enabled'] = false\ndefault['yum']['epel-testing-debuginfo']['managed'] = false\n```\n\n``` ruby\ndefault['yum']['epel-testing-source']['repositoryid'] = 'epel-testing-source'\ndefault['yum']['epel-testing-source']['description'] = 'Extra Packages for Enterprise Linux 6 - Testing - $basearch Source'\ndefault['yum']['epel-testing-source']['mirrorlist'] = 'https://mirrors.fedoraproject.org/metalink?repo=testing-source-epel6&arch=$basearch'\ndefault['yum']['epel-testing-source']['gpgkey'] = 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6'\ndefault['yum']['epel-testing-source']['failovermethod'] = 'priority'\ndefault['yum']['epel-testing-source']['gpgcheck'] = true\ndefault['yum']['epel-testing-source']['enabled'] = false\ndefault['yum']['epel-testing-source']['managed'] = false\n```\n\nRecipes\n-------\n* default - Walks through node attributes and feeds a yum_resource\n parameters. The following is an example a resource generated by the\n recipe during compilation.\n\n```ruby\n yum_repository 'epel' do\n mirrorlist 'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch'\n description 'Extra Packages for Enterprise Linux 5 - $basearch'\n enabled true\n gpgcheck true\n gpgkey 'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL'\n end\n```\n\nUsage Example\n-------------\nTo disable the epel repository through a Role or Environment definition\n\n```\ndefault_attributes(\n :yum => {\n :epel => {\n :enabled => {\n false\n }\n }\n }\n )\n```\n\nUncommonly used repositoryids are not managed by default. This is\nspeeds up integration testing pipelines by avoiding yum-cache builds\nthat nobody cares about. To enable the epel-testing repository with a\nwrapper cookbook, place the following in a recipe:\n\n```\nnode.default['yum']['epel-testing']['enabled'] = true\nnode.default['yum']['epel-testing']['managed'] = true\ninclude_recipe 'yum-epel'\n```\n\nMore Examples\n-------------\nPoint the epel repositories at an internally hosted server.\n\n```\nnode.default['yum']['epel']['enabled'] = true\nnode.default['yum']['epel']['mirrorlist'] = nil\nnode.default['yum']['epel']['baseurl'] = 'https://internal.example.com/centos/6/os/x86_64'\nnode.default['yum']['epel']['sslverify'] = false\n\ninclude_recipe 'yum-epel'\n```\n\nLicense & Authors\n-----------------\n- Author:: Sean OMeara ()\n\n```text\nCopyright:: 2011-2013 Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n", + "maintainer": "Chef", + "maintainer_email": "Sean OMeara ", + "license": "Apache 2.0", + "platforms": { + }, + "dependencies": { + "yum": "~> 3.0" + }, + "recommendations": { + }, + "suggestions": { + }, + "conflicting": { + }, + "providing": { + }, + "replacing": { + }, + "attributes": { + }, + "groupings": { + }, + "recipes": { + } +} \ No newline at end of file diff --git a/cookbooks/yum-epel/metadata.rb b/cookbooks/yum-epel/metadata.rb new file mode 100644 index 0000000..3b9958b --- /dev/null +++ b/cookbooks/yum-epel/metadata.rb @@ -0,0 +1,9 @@ +name 'yum-epel' +maintainer 'Chef' +maintainer_email 'Sean OMeara ' +license 'Apache 2.0' +description 'Installs/Configures yum-epel' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '0.3.6' + +depends 'yum', '~> 3.0' diff --git a/cookbooks/yum-epel/recipes/default.rb b/cookbooks/yum-epel/recipes/default.rb index 02f75f3..b8811ba 100644 --- a/cookbooks/yum-epel/recipes/default.rb +++ b/cookbooks/yum-epel/recipes/default.rb @@ -1,9 +1,8 @@ # -# Author:: Sean OMeara () -# Cookbook:: yum-epel -# Recipe:: default +# Author:: Sean OMeara () +# Recipe:: yum-epel::default # -# Copyright:: 2013-2016, Chef Software, Inc. +# Copyright 2013, Chef # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,11 +16,41 @@ # See the License for the specific language governing permissions and # limitations under the License. -node['yum-epel']['repos'].each do |repo| - next unless node['yum'][repo]['managed'] - yum_repository repo do - node['yum'][repo].each do |config, value| - send(config.to_sym, value) unless value.nil? || config == 'managed' +%w{ + epel epel-debuginfo epel-source + epel-testing epel-testing-debuginfo epel-testing-source + }.each do |repo| + + if node['yum'][repo]['managed'] + yum_repository repo do + description node['yum'][repo]['description'] + baseurl node['yum'][repo]['baseurl'] + mirrorlist node['yum'][repo]['mirrorlist'] + gpgcheck node['yum'][repo]['gpgcheck'] + gpgkey node['yum'][repo]['gpgkey'] + enabled node['yum'][repo]['enabled'] + cost node['yum'][repo]['cost'] + exclude node['yum'][repo]['exclude'] + enablegroups node['yum'][repo]['enablegroups'] + failovermethod node['yum'][repo]['failovermethod'] + http_caching node['yum'][repo]['http_caching'] + include_config node['yum'][repo]['include_config'] + includepkgs node['yum'][repo]['includepkgs'] + keepalive node['yum'][repo]['keepalive'] + max_retries node['yum'][repo]['max_retries'] + metadata_expire node['yum'][repo]['metadata_expire'] + mirror_expire node['yum'][repo]['mirror_expire'] + priority node['yum'][repo]['priority'] + proxy node['yum'][repo]['proxy'] + proxy_username node['yum'][repo]['proxy_username'] + proxy_password node['yum'][repo]['proxy_password'] + repositoryid node['yum'][repo]['repositoryid'] + sslcacert node['yum'][repo]['sslcacert'] + sslclientcert node['yum'][repo]['sslclientcert'] + sslclientkey node['yum'][repo]['sslclientkey'] + sslverify node['yum'][repo]['sslverify'] + timeout node['yum'][repo]['timeout'] + action :create end end end diff --git a/cookbooks/yum-mysql-community/CHANGELOG.md b/cookbooks/yum-mysql-community/CHANGELOG.md deleted file mode 100644 index 77d7ed7..0000000 --- a/cookbooks/yum-mysql-community/CHANGELOG.md +++ /dev/null @@ -1,82 +0,0 @@ -yum-mysql-community Cookbook CHANGELOG ---------------------------------------- -This file is used to list changes made in each version of the yum-mysql-community cookbook. - -v0.1.21 (2015-12-01) --------------------- -- Fixing if/unless logic in recipes - -v0.1.20 (2015-11-30) --------------------- -- Fixed attributes with a false value not being passed - -v0.1.19 (2015-10-28) --------------------- -- Fixing Chef 13 nil property deprecation warnings - -v0.1.18 (2015-09-21) --------------------- -- Added Travis CI config for lint and unit testing -- Added Chef standard Rubocop file and resolved all warnings -- Added Chef standard chefignore and .gitignore files -- Add supported platforms to the metadata -- Added source_url and issues_url to the metadata -- Added long_description to the metadata -- Updated and expanded development dependencies in the Gemfile -- Added contributing, testing, and maintainers docs -- Added platform requirements to the readme -- Added Travis and cookbook version badges to the readme -- Update Chefspec to 4.X format - -v0.1.17 (2015-04-06) --------------------- -- Updating pubkey link from someara to chef-client github orgs - -v0.1.16 (2015-03-25) --------------------- -- Adding support Amazon Linux 2015.03 to all channels - -v0.1.15 (2015-03-25) --------------------- -- Added support for amazon linux 2015.03 - -v0.1.14 (2015-03-12) --------------------- -- The content of 0.1.13 is questionable: didn't have changelog entry, may have had merged attribute change, but let's be clear and say at least this version 0.1.14 is the right thing. - -v0.1.13 (2015-03-12) --------------------- -- #3 corrected typo in public key attribute - -v0.1.12 (2015-01-20) --------------------- -- Minor style updates - -v0.1.11 (2014-07-21) --------------------- -- Adding RHEL-7 support - -v0.1.10 (2014-07-21) --------------------- -- Adding mysql-5.7 and centos 7 support - -v0.1.8 (2014-06-18) -------------------- -- Updating to support real RHEL - -v0.1.6 (2014-06-16) -------------------- -Fixing typo in mysql55-community attributes - -v0.1.4 (2014-06-13) -------------------- -- updating url to keys in cookbook attributes - -v0.1.2 (2014-06-11) -------------------- -#1 - Move files/mysql_pubkey.asc to files/default/mysql_pubkey.asc - -v0.1.0 (2014-04-30) -------------------- -Initial release - diff --git a/cookbooks/yum-mysql-community/MAINTAINERS.md b/cookbooks/yum-mysql-community/MAINTAINERS.md deleted file mode 100644 index 2cf4d2f..0000000 --- a/cookbooks/yum-mysql-community/MAINTAINERS.md +++ /dev/null @@ -1,19 +0,0 @@ - - -# Maintainers -This file lists how this cookbook project is maintained. When making changes to the system, this -file tells you who needs to review your patch - you need a simple majority of maintainers -for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need -to not receive a veto from a Lieutenant or the Project Lead. - -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) -for details on the process and how to become a maintainer or the project lead. - -# Project Maintainer -* [Jennifer Davis](https://github.com/sigje) - -# Maintainers -* [Jennifer Davis](https://github.com/sigje) -* [Sean OMeara](https://github.com/someara) -* [Tim Smith](https://github.com/tas50) -* [Thom May](https://github.com/thommay) diff --git a/cookbooks/yum-mysql-community/README.md b/cookbooks/yum-mysql-community/README.md deleted file mode 100644 index 7bae244..0000000 --- a/cookbooks/yum-mysql-community/README.md +++ /dev/null @@ -1,131 +0,0 @@ -# yum-mysql-community Cookbook -[![Build Status](https://travis-ci.org/chef-cookbooks/yum-mysql-community.svg?branch=master)](http://travis-ci.org/chef-cookbooks/yum-mysql-community) [![Cookbook Version](https://img.shields.io/cookbook/v/yum-mysql-community.svg)](https://supermarket.chef.io/cookbooks/yum-mysql-community) - -The yum-mysql-community cookbook takes over management of the default repository ids shipped with epel-release. It allows attribute manipulation of `mysql-connectors-community`, `mysql56-community`, and `mysql57-community-dmr`. - -## Requirements -### Platforms -- RHEL/CentOS and derivatives -- Fedora - -### Chef -- Chef 11+ - -### Cookbooks -- yum version 3.0.0 or higher -- yum-epel - -## Attributes -The following attributes are set by default - -```ruby -default['yum']['mysql-connectors-community']['repositoryid'] = 'mysql-connectors-community' -default['yum']['mysql-connectors-community']['description'] = 'MySQL Connectors Community' -default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/$releasever/$basearch/' -default['yum']['mysql-connectors-community']['gpgkey'] = 'https://raw.githubusercontent.com/rs-services/equinix-public/master/cookbooks/db_mysql/files/centos/mysql_pubkey.asc' -default['yum']['mysql-connectors-community']['failovermethod'] = 'priority' -default['yum']['mysql-connectors-community']['gpgcheck'] = true -default['yum']['mysql-connectors-community']['enabled'] = true -``` - -```ruby -default['yum']['mysql56-community']['repositoryid'] = 'mysql56-community' -default['yum']['mysql56-community']['description'] = 'MySQL 5.6 Community Server' -default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql56-community/el/$releasever/$basearch/' -default['yum']['mysql56-community']['gpgkey'] = 'https://raw.githubusercontent.com/rs-services/equinix-public/master/cookbooks/db_mysql/files/centos/mysql_pubkey.asc' -default['yum']['mysql56-community']['failovermethod'] = 'priority' -default['yum']['mysql56-community']['gpgcheck'] = true -default['yum']['mysql56-community']['enabled'] = true -``` - -```ruby -default['yum']['mysql57-community-dmr']['repositoryid'] = 'mysql57-community-dmr' -default['yum']['mysql57-community-dmr']['description'] = 'MySQL 5.7 Community Server Development Milestone Release' -default['yum']['mysql57-community-dmr']['baseurl'] = 'http://repo.mysql.com/yum/mysql56-community/el/$releasever/$basearch/' -default['yum']['mysql57-community-dmr']['gpgkey'] = 'https://raw.githubusercontent.com/rs-services/equinix-public/master/cookbooks/db_mysql/files/centos/mysql_pubkey.asc' -default['yum']['mysql57-community-dmr']['failovermethod'] = 'priority' -default['yum']['mysql57-community-dmr']['gpgcheck'] = true -default['yum']['mysql57-community-dmr']['enabled'] = true -``` - -## Recipes -- mysql55 - Sets up the mysql56-community repository on supported -- platforms - -```ruby - yum_repository 'mysql55-community' do - mirrorlist 'http://repo.mysql.com/yum/mysql55-community/el/$releasever/$basearch/' - description '' - enabled true - gpgcheck true - end -``` - -- mysql56 - Sets up the mysql56-community repository on supported -- platforms - -```ruby - yum_repository 'mysql56-community' do - mirrorlist 'http://repo.mysql.com/yum/mysql56-community/el/$releasever/$basearch/' - description '' - enabled true - gpgcheck true - end -``` - -- connectors - Sets up the mysql-connectors-community repository on supported -- platforms - -## Usage Example -To disable the epel repository through a Role or Environment definition - -``` -default_attributes( - :yum => { - :mysql57-community-dmr => { - :enabled => { - false - } - } - } - ) -``` - -Uncommonly used repositoryids are not managed by default. This is speeds up integration testing pipelines by avoiding yum-cache builds that nobody cares about. To enable the epel-testing repository with a wrapper cookbook, place the following in a recipe: - -``` -node.default['yum']['mysql57-community-dmr']['enabled'] = true -node.default['yum']['mysql57-community-dmr']['managed'] = true -include_recipe 'mysql57-community-dmr' -``` - -## More Examples -Point the mysql56-community repositories at an internally hosted server. - -``` -node.default['yum']['mysql56-community']['enabled'] = true -node.default['yum']['mysql56-community']['mirrorlist'] = nil -node.default['yum']['mysql56-community']['baseurl'] = 'https://internal.example.com/mysql/mysql56-community/' -node.default['yum']['mysql56-community']['sslverify'] = false - -include_recipe 'mysql56-community' -``` - -## License & Authors -**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io)) - -**Copyright:** 2011-2015, Chef Software, Inc. - -``` -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` diff --git a/cookbooks/yum-mysql-community/attributes/mysql-connectors-community.rb b/cookbooks/yum-mysql-community/attributes/mysql-connectors-community.rb deleted file mode 100644 index 2ffd3d6..0000000 --- a/cookbooks/yum-mysql-community/attributes/mysql-connectors-community.rb +++ /dev/null @@ -1,35 +0,0 @@ -default['yum']['mysql-connectors-community']['repositoryid'] = 'mysql-connectors-community' -default['yum']['mysql-connectors-community']['gpgkey'] = 'https://raw.githubusercontent.com/chef-cookbooks/yum-mysql-community/master/files/default/mysql_pubkey.asc' -default['yum']['mysql-connectors-community']['description'] = 'MySQL Connectors Community' -default['yum']['mysql-connectors-community']['failovermethod'] = 'priority' -default['yum']['mysql-connectors-community']['gpgcheck'] = true -default['yum']['mysql-connectors-community']['enabled'] = true - -case node['platform_family'] -when 'rhel' - case node['platform'] - when 'amazon' - case node['platform_version'].to_i - when 2013 - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/6/$basearch/' - when 2014 - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/6/$basearch/' - when 2015 - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/6/$basearch/' - end - when 'redhat' - case node['platform_version'].to_i - when 5 - # Real Redhat identifies $releasever as 5Server and 6Server - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/5/$basearch/' - when 6 - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/6/$basearch/' - when 7 - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/7/$basearch/' - end - else # other rhel - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/el/$releasever/$basearch/' - end -when 'fedora' - default['yum']['mysql-connectors-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-connectors-community/fc/$releasever/$basearch/' -end diff --git a/cookbooks/yum-mysql-community/attributes/mysql55-community.rb b/cookbooks/yum-mysql-community/attributes/mysql55-community.rb deleted file mode 100644 index 73e2efd..0000000 --- a/cookbooks/yum-mysql-community/attributes/mysql55-community.rb +++ /dev/null @@ -1,33 +0,0 @@ -default['yum']['mysql55-community']['repositoryid'] = 'mysql55-community' -default['yum']['mysql55-community']['gpgkey'] = 'https://raw.githubusercontent.com/chef-cookbooks/yum-mysql-community/master/files/default/mysql_pubkey.asc' -default['yum']['mysql55-community']['description'] = 'MySQL 5.5 Community Server' -default['yum']['mysql55-community']['failovermethod'] = 'priority' -default['yum']['mysql55-community']['gpgcheck'] = true -default['yum']['mysql55-community']['enabled'] = true - -case node['platform_family'] -when 'rhel' - case node['platform'] - when 'amazon' - case node['platform_version'].to_i - when 2013 - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/6/$basearch/' - when 2014 - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/6/$basearch/' - when 2015 - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/6/$basearch/' - end - when 'redhat' - case node['platform_version'].to_i - when 5 - # Real Redhat identifies $releasever as 5Server and 6Server - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/5/$basearch/' - when 6 - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/6/$basearch/' - when 7 - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/7/$basearch/' - end - else # other rhel. only 6 and 7 for now - default['yum']['mysql55-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.5-community/el/$releasever/$basearch/' - end -end diff --git a/cookbooks/yum-mysql-community/attributes/mysql56-community.rb b/cookbooks/yum-mysql-community/attributes/mysql56-community.rb deleted file mode 100644 index c301a57..0000000 --- a/cookbooks/yum-mysql-community/attributes/mysql56-community.rb +++ /dev/null @@ -1,35 +0,0 @@ -default['yum']['mysql56-community']['repositoryid'] = 'mysql56-community' -default['yum']['mysql56-community']['gpgkey'] = 'https://raw.githubusercontent.com/chef-cookbooks/yum-mysql-community/master/files/default/mysql_pubkey.asc' -default['yum']['mysql56-community']['description'] = 'MySQL 5.6 Community Server' -default['yum']['mysql56-community']['failovermethod'] = 'priority' -default['yum']['mysql56-community']['gpgcheck'] = true -default['yum']['mysql56-community']['enabled'] = true - -case node['platform_family'] -when 'rhel' - case node['platform'] - when 'amazon' - case node['platform_version'].to_i - when 2013 - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/6/$basearch/' - when 2014 - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/6/$basearch/' - when 2015 - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/6/$basearch/' - end - when 'redhat' - case node['platform_version'].to_i - when 5 - # Real Redhat identifies $releasever as 5Server and 6Server - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/5/$basearch/' - when 6 - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/6/$basearch/' - when 7 - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/7/$basearch/' - end - else # other rhel - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/el/$releasever/$basearch/' - end -when 'fedora' - default['yum']['mysql56-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.6-community/fc/$releasever/$basearch/' -end diff --git a/cookbooks/yum-mysql-community/attributes/mysql57-community.rb b/cookbooks/yum-mysql-community/attributes/mysql57-community.rb deleted file mode 100644 index ad8e55c..0000000 --- a/cookbooks/yum-mysql-community/attributes/mysql57-community.rb +++ /dev/null @@ -1,35 +0,0 @@ -default['yum']['mysql57-community']['repositoryid'] = 'mysql57-community' -default['yum']['mysql57-community']['gpgkey'] = 'https://raw.githubusercontent.com/chef-cookbooks/yum-mysql-community/master/files/default/mysql_pubkey.asc' -default['yum']['mysql57-community']['description'] = 'MySQL 5.7 Community Server' -default['yum']['mysql57-community']['failovermethod'] = 'priority' -default['yum']['mysql57-community']['gpgcheck'] = true -default['yum']['mysql57-community']['enabled'] = true - -case node['platform_family'] -when 'rhel' - case node['platform'] - when 'amazon' - case node['platform_version'].to_i - when 2013 - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/' - when 2014 - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/' - when 2015 - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/' - end - when 'redhat' - case node['platform_version'].to_i - when 5 - # Real Redhat identifies $releasever as 5Server and 6Server - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/5/$basearch/' - when 6 - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/' - when 7 - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/7/$basearch/' - end - else # other rhel - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/el/$releasever/$basearch/' - end -when 'fedora' - default['yum']['mysql57-community']['baseurl'] = 'http://repo.mysql.com/yum/mysql-5.7-community/fc/$releasever/$basearch/' -end diff --git a/cookbooks/yum-mysql-community/files/default/mysql_pubkey.asc b/cookbooks/yum-mysql-community/files/default/mysql_pubkey.asc deleted file mode 100644 index 8009b88..0000000 --- a/cookbooks/yum-mysql-community/files/default/mysql_pubkey.asc +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.5 (GNU/Linux) - -mQGiBD4+owwRBAC14GIfUfCyEDSIePvEW3SAFUdJBtoQHH/nJKZyQT7h9bPlUWC3 -RODjQReyCITRrdwyrKUGku2FmeVGwn2u2WmDMNABLnpprWPkBdCk96+OmSLN9brZ -fw2vOUgCmYv2hW0hyDHuvYlQA/BThQoADgj8AW6/0Lo7V1W9/8VuHP0gQwCgvzV3 -BqOxRznNCRCRxAuAuVztHRcEAJooQK1+iSiunZMYD1WufeXfshc57S/+yeJkegNW -hxwR9pRWVArNYJdDRT+rf2RUe3vpquKNQU/hnEIUHJRQqYHo8gTxvxXNQc7fJYLV -K2HtkrPbP72vwsEKMYhhr0eKCbtLGfls9krjJ6sBgACyP/Vb7hiPwxh6rDZ7ITnE -kYpXBACmWpP8NJTkamEnPCia2ZoOHODANwpUkP43I7jsDmgtobZX9qnrAXw+uNDI -QJEXM6FSbi0LLtZciNlYsafwAPEOMDKpMqAK6IyisNtPvaLd8lH0bPAnWqcyefep -rv0sxxqUEMcM3o7wwgfN83POkDasDbs3pjwPhxvhz6//62zQJ7Q7TXlTUUwgUGFj -a2FnZSBzaWduaW5nIGtleSAod3d3Lm15c3FsLmNvbSkgPGJ1aWxkQG15c3FsLmNv -bT6IXQQTEQIAHQULBwoDBAMVAwIDFgIBAheABQJLcC5lBQkQ8/JZAAoJEIxxjTtQ -cuH1oD4AoIcOQ4EoGsZvy06D0Ei5vcsWEy8dAJ4g46i3WEcdSWxMhcBSsPz65sh5 -lohMBBMRAgAMBQI+PqPRBYMJZgC7AAoJEElQ4SqycpHyJOEAn1mxHijft00bKXvu -cSo/pECUmppiAJ41M9MRVj5VcdH/KN/KjRtW6tHFPYhMBBMRAgAMBQI+QoIDBYMJ -YiKJAAoJELb1zU3GuiQ/lpEAoIhpp6BozKI8p6eaabzF5MlJH58pAKCu/ROofK8J -Eg2aLos+5zEYrB/LsrkCDQQ+PqMdEAgA7+GJfxbMdY4wslPnjH9rF4N2qfWsEN/l -xaZoJYc3a6M02WCnHl6ahT2/tBK2w1QI4YFteR47gCvtgb6O1JHffOo2HfLmRDRi -Rjd1DTCHqeyX7CHhcghj/dNRlW2Z0l5QFEcmV9U0Vhp3aFfWC4Ujfs3LU+hkAWzE -7zaD5cH9J7yv/6xuZVw411x0h4UqsTcWMu0iM1BzELqX1DY7LwoPEb/O9Rkbf4fm -Le11EzIaCa4PqARXQZc4dhSinMt6K3X4BrRsKTfozBu74F47D8Ilbf5vSYHbuE5p -/1oIDznkg/p8kW+3FxuWrycciqFTcNz215yyX39LXFnlLzKUb/F5GwADBQf+Lwqq -a8CGrRfsOAJxim63CHfty5mUc5rUSnTslGYEIOCR1BeQauyPZbPDsDD9MZ1ZaSaf -anFvwFG6Llx9xkU7tzq+vKLoWkm4u5xf3vn55VjnSd1aQ9eQnUcXiL4cnBGoTbOW -I39EcyzgslzBdC++MPjcQTcA7p6JUVsP6oAB3FQWg54tuUo0Ec8bsM8b3Ev42Lmu -QT5NdKHGwHsXTPtl0klk4bQk4OajHsiy1BMahpT27jWjJlMiJc+IWJ0mghkKHt92 -6s/ymfdf5HkdQ1cyvsz5tryVI3Fx78XeSYfQvuuwqp2H139pXGEkg0n6KdUOetdZ -Whe70YGNPw1yjWJT1IhMBBgRAgAMBQI+PqMdBQkJZgGAAAoJEIxxjTtQcuH17p4A -n3r1QpVC9yhnW2cSAjq+kr72GX0eAJ4295kl6NxYEuFApmr1+0uUq/SlsQ== -=Mski ------END PGP PUBLIC KEY BLOCK----- diff --git a/cookbooks/yum-mysql-community/metadata.json b/cookbooks/yum-mysql-community/metadata.json deleted file mode 100644 index 0e996cb..0000000 --- a/cookbooks/yum-mysql-community/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"yum-mysql-community","version":"0.1.21","description":"Installs/Configures yum-mysql-community","long_description":"","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0"},"dependencies":{"yum":">= 3.2"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file diff --git a/cookbooks/yum-mysql-community/recipes/connectors.rb b/cookbooks/yum-mysql-community/recipes/connectors.rb deleted file mode 100644 index 40fc983..0000000 --- a/cookbooks/yum-mysql-community/recipes/connectors.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Sean OMeara () -# Recipe:: yum-mysql-community::connectors -# -# Copyright 2014-2015, Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -yum_repository 'mysql-connectors-community' do - description node['yum']['mysql-connectors-community']['description'] unless node['yum']['mysql-connectors-community']['description'].nil? - baseurl node['yum']['mysql-connectors-community']['baseurl'] unless node['yum']['mysql-connectors-community']['baseurl'].nil? - mirrorlist node['yum']['mysql-connectors-community']['mirrorlist'] unless node['yum']['mysql-connectors-community']['mirrorlist'].nil? - gpgcheck node['yum']['mysql-connectors-community']['gpgcheck'] unless node['yum']['mysql-connectors-community']['gpgcheck'].nil? - gpgkey node['yum']['mysql-connectors-community']['gpgkey'] unless node['yum']['mysql-connectors-community']['gpgkey'].nil? - enabled node['yum']['mysql-connectors-community']['enabled'] unless node['yum']['mysql-connectors-community']['enabled'].nil? - cost node['yum']['mysql-connectors-community']['cost'] unless node['yum']['mysql-connectors-community']['cost'].nil? - exclude node['yum']['mysql-connectors-community']['exclude'] unless node['yum']['mysql-connectors-community']['exclude'].nil? - enablegroups node['yum']['mysql-connectors-community']['enablegroups'] unless node['yum']['mysql-connectors-community']['enablegroups'].nil? - failovermethod node['yum']['mysql-connectors-community']['failovermethod'] unless node['yum']['mysql-connectors-community']['failovermethod'].nil? - http_caching node['yum']['mysql-connectors-community']['http_caching'] unless node['yum']['mysql-connectors-community']['http_caching'].nil? - include_config node['yum']['mysql-connectors-community']['include_config'] unless node['yum']['mysql-connectors-community']['include_config'].nil? - includepkgs node['yum']['mysql-connectors-community']['includepkgs'] unless node['yum']['mysql-connectors-community']['includepkgs'].nil? - keepalive node['yum']['mysql-connectors-community']['keepalive'] unless node['yum']['mysql-connectors-community']['keepalive'].nil? - max_retries node['yum']['mysql-connectors-community']['max_retries'] unless node['yum']['mysql-connectors-community']['max_retries'].nil? - metadata_expire node['yum']['mysql-connectors-community']['metadata_expire'] unless node['yum']['mysql-connectors-community']['metadata_expire'].nil? - mirror_expire node['yum']['mysql-connectors-community']['mirror_expire'] unless node['yum']['mysql-connectors-community']['mirror_expire'].nil? - priority node['yum']['mysql-connectors-community']['priority'] unless node['yum']['mysql-connectors-community']['priority'].nil? - proxy node['yum']['mysql-connectors-community']['proxy'] unless node['yum']['mysql-connectors-community']['proxy'].nil? - proxy_username node['yum']['mysql-connectors-community']['proxy_username'] unless node['yum']['mysql-connectors-community']['proxy_username'].nil? - proxy_password node['yum']['mysql-connectors-community']['proxy_password'] unless node['yum']['mysql-connectors-community']['proxy_password'].nil? - repositoryid node['yum']['mysql-connectors-community']['repositoryid'] unless node['yum']['mysql-connectors-community']['repositoryid'].nil? - sslcacert node['yum']['mysql-connectors-community']['sslcacert'] unless node['yum']['mysql-connectors-community']['sslcacert'].nil? - sslclientcert node['yum']['mysql-connectors-community']['sslclientcert'] unless node['yum']['mysql-connectors-community']['sslclientcert'].nil? - sslclientkey node['yum']['mysql-connectors-community']['sslclientkey'] unless node['yum']['mysql-connectors-community']['sslclientkey'].nil? - sslverify node['yum']['mysql-connectors-community']['sslverify'] unless node['yum']['mysql-connectors-community']['sslverify'].nil? - timeout node['yum']['mysql-connectors-community']['timeout'] unless node['yum']['mysql-connectors-community']['timeout'].nil? - action :create -end diff --git a/cookbooks/yum-mysql-community/recipes/mysql55.rb b/cookbooks/yum-mysql-community/recipes/mysql55.rb deleted file mode 100644 index 6b6d46c..0000000 --- a/cookbooks/yum-mysql-community/recipes/mysql55.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Sean OMeara () -# Recipe:: yum-mysql-community::mysql55 -# -# Copyright 2014-2015, Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -yum_repository 'mysql55-community' do - description node['yum']['mysql55-community']['description'] unless node['yum']['mysql55-community']['description'].nil? - baseurl node['yum']['mysql55-community']['baseurl'] unless node['yum']['mysql55-community']['baseurl'].nil? - mirrorlist node['yum']['mysql55-community']['mirrorlist'] unless node['yum']['mysql55-community']['mirrorlist'].nil? - gpgcheck node['yum']['mysql55-community']['gpgcheck'] unless node['yum']['mysql55-community']['gpgcheck'].nil? - gpgkey node['yum']['mysql55-community']['gpgkey'] unless node['yum']['mysql55-community']['gpgkey'].nil? - enabled node['yum']['mysql55-community']['enabled'] unless node['yum']['mysql55-community']['enabled'].nil? - cost node['yum']['mysql55-community']['cost'] unless node['yum']['mysql55-community']['cost'].nil? - exclude node['yum']['mysql55-community']['exclude'] unless node['yum']['mysql55-community']['exclude'].nil? - enablegroups node['yum']['mysql55-community']['enablegroups'] unless node['yum']['mysql55-community']['enablegroups'].nil? - failovermethod node['yum']['mysql55-community']['failovermethod'] unless node['yum']['mysql55-community']['failovermethod'].nil? - http_caching node['yum']['mysql55-community']['http_caching'] unless node['yum']['mysql55-community']['http_caching'].nil? - include_config node['yum']['mysql55-community']['include_config'] unless node['yum']['mysql55-community']['include_config'].nil? - includepkgs node['yum']['mysql55-community']['includepkgs'] unless node['yum']['mysql55-community']['includepkgs'].nil? - keepalive node['yum']['mysql55-community']['keepalive'] unless node['yum']['mysql55-community']['keepalive'].nil? - max_retries node['yum']['mysql55-community']['max_retries'] unless node['yum']['mysql55-community']['max_retries'].nil? - metadata_expire node['yum']['mysql55-community']['metadata_expire'] unless node['yum']['mysql55-community']['metadata_expire'].nil? - mirror_expire node['yum']['mysql55-community']['mirror_expire'] unless node['yum']['mysql55-community']['mirror_expire'].nil? - priority node['yum']['mysql55-community']['priority'] unless node['yum']['mysql55-community']['priority'].nil? - proxy node['yum']['mysql55-community']['proxy'] unless node['yum']['mysql55-community']['proxy'].nil? - proxy_username node['yum']['mysql55-community']['proxy_username'] unless node['yum']['mysql55-community']['proxy_username'].nil? - proxy_password node['yum']['mysql55-community']['proxy_password'] unless node['yum']['mysql55-community']['proxy_password'].nil? - repositoryid node['yum']['mysql55-community']['repositoryid'] unless node['yum']['mysql55-community']['repositoryid'].nil? - sslcacert node['yum']['mysql55-community']['sslcacert'] unless node['yum']['mysql55-community']['sslcacert'].nil? - sslclientcert node['yum']['mysql55-community']['sslclientcert'] unless node['yum']['mysql55-community']['sslclientcert'].nil? - sslclientkey node['yum']['mysql55-community']['sslclientkey'] unless node['yum']['mysql55-community']['sslclientkey'].nil? - sslverify node['yum']['mysql55-community']['sslverify'] unless node['yum']['mysql55-community']['sslverify'].nil? - timeout node['yum']['mysql55-community']['timeout'] unless node['yum']['mysql55-community']['timeout'].nil? - action :create -end diff --git a/cookbooks/yum-mysql-community/recipes/mysql56.rb b/cookbooks/yum-mysql-community/recipes/mysql56.rb deleted file mode 100644 index 5adb378..0000000 --- a/cookbooks/yum-mysql-community/recipes/mysql56.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Sean OMeara () -# Recipe:: yum-mysql-community::mysql56-community -# -# Copyright 2014-2015, Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -yum_repository 'mysql56-community' do - description node['yum']['mysql56-community']['description'] unless node['yum']['mysql56-community']['description'].nil? - baseurl node['yum']['mysql56-community']['baseurl'] unless node['yum']['mysql56-community']['baseurl'].nil? - mirrorlist node['yum']['mysql56-community']['mirrorlist'] unless node['yum']['mysql56-community']['mirrorlist'].nil? - gpgcheck node['yum']['mysql56-community']['gpgcheck'] unless node['yum']['mysql56-community']['gpgcheck'].nil? - gpgkey node['yum']['mysql56-community']['gpgkey'] unless node['yum']['mysql56-community']['gpgkey'].nil? - enabled node['yum']['mysql56-community']['enabled'] unless node['yum']['mysql56-community']['enabled'].nil? - cost node['yum']['mysql56-community']['cost'] unless node['yum']['mysql56-community']['cost'].nil? - exclude node['yum']['mysql56-community']['exclude'] unless node['yum']['mysql56-community']['exclude'].nil? - enablegroups node['yum']['mysql56-community']['enablegroups'] unless node['yum']['mysql56-community']['enablegroups'].nil? - failovermethod node['yum']['mysql56-community']['failovermethod'] unless node['yum']['mysql56-community']['failovermethod'].nil? - http_caching node['yum']['mysql56-community']['http_caching'] unless node['yum']['mysql56-community']['http_caching'].nil? - include_config node['yum']['mysql56-community']['include_config'] unless node['yum']['mysql56-community']['include_config'].nil? - includepkgs node['yum']['mysql56-community']['includepkgs'] unless node['yum']['mysql56-community']['includepkgs'].nil? - keepalive node['yum']['mysql56-community']['keepalive'] unless node['yum']['mysql56-community']['keepalive'].nil? - max_retries node['yum']['mysql56-community']['max_retries'] unless node['yum']['mysql56-community']['max_retries'].nil? - metadata_expire node['yum']['mysql56-community']['metadata_expire'] unless node['yum']['mysql56-community']['metadata_expire'].nil? - mirror_expire node['yum']['mysql56-community']['mirror_expire'] unless node['yum']['mysql56-community']['mirror_expire'].nil? - priority node['yum']['mysql56-community']['priority'] unless node['yum']['mysql56-community']['priority'].nil? - proxy node['yum']['mysql56-community']['proxy'] unless node['yum']['mysql56-community']['proxy'].nil? - proxy_username node['yum']['mysql56-community']['proxy_username'] unless node['yum']['mysql56-community']['proxy_username'].nil? - proxy_password node['yum']['mysql56-community']['proxy_password'] unless node['yum']['mysql56-community']['proxy_password'].nil? - repositoryid node['yum']['mysql56-community']['repositoryid'] unless node['yum']['mysql56-community']['repositoryid'].nil? - sslcacert node['yum']['mysql56-community']['sslcacert'] unless node['yum']['mysql56-community']['sslcacert'].nil? - sslclientcert node['yum']['mysql56-community']['sslclientcert'] unless node['yum']['mysql56-community']['sslclientcert'].nil? - sslclientkey node['yum']['mysql56-community']['sslclientkey'] unless node['yum']['mysql56-community']['sslclientkey'].nil? - sslverify node['yum']['mysql56-community']['sslverify'] unless node['yum']['mysql56-community']['sslverify'].nil? - timeout node['yum']['mysql56-community']['timeout'] unless node['yum']['mysql56-community']['timeout'].nil? - action :create -end diff --git a/cookbooks/yum-mysql-community/recipes/mysql57.rb b/cookbooks/yum-mysql-community/recipes/mysql57.rb deleted file mode 100644 index ba617c1..0000000 --- a/cookbooks/yum-mysql-community/recipes/mysql57.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Sean OMeara () -# Recipe:: yum-mysql-community::mysql57-community -# -# Copyright 2014-2015, Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -yum_repository 'mysql57-community' do - description node['yum']['mysql57-community']['description'] unless node['yum']['mysql57-community']['description'].nil? - baseurl node['yum']['mysql57-community']['baseurl'] unless node['yum']['mysql57-community']['baseurl'].nil? - mirrorlist node['yum']['mysql57-community']['mirrorlist'] unless node['yum']['mysql57-community']['mirrorlist'].nil? - gpgcheck node['yum']['mysql57-community']['gpgcheck'] unless node['yum']['mysql57-community']['gpgcheck'].nil? - gpgkey node['yum']['mysql57-community']['gpgkey'] unless node['yum']['mysql57-community']['gpgkey'].nil? - enabled node['yum']['mysql57-community']['enabled'] unless node['yum']['mysql57-community']['enabled'].nil? - cost node['yum']['mysql57-community']['cost'] unless node['yum']['mysql57-community']['cost'].nil? - exclude node['yum']['mysql57-community']['exclude'] unless node['yum']['mysql57-community']['exclude'].nil? - enablegroups node['yum']['mysql57-community']['enablegroups'] unless node['yum']['mysql57-community']['enablegroups'].nil? - failovermethod node['yum']['mysql57-community']['failovermethod'] unless node['yum']['mysql57-community']['failovermethod'].nil? - http_caching node['yum']['mysql57-community']['http_caching'] unless node['yum']['mysql57-community']['http_caching'].nil? - include_config node['yum']['mysql57-community']['include_config'] unless node['yum']['mysql57-community']['include_config'].nil? - includepkgs node['yum']['mysql57-community']['includepkgs'] unless node['yum']['mysql57-community']['includepkgs'].nil? - keepalive node['yum']['mysql57-community']['keepalive'] unless node['yum']['mysql57-community']['keepalive'].nil? - max_retries node['yum']['mysql57-community']['max_retries'] unless node['yum']['mysql57-community']['max_retries'].nil? - metadata_expire node['yum']['mysql57-community']['metadata_expire'] unless node['yum']['mysql57-community']['metadata_expire'].nil? - mirror_expire node['yum']['mysql57-community']['mirror_expire'] unless node['yum']['mysql57-community']['mirror_expire'].nil? - priority node['yum']['mysql57-community']['priority'] unless node['yum']['mysql57-community']['priority'].nil? - proxy node['yum']['mysql57-community']['proxy'] unless node['yum']['mysql57-community']['proxy'].nil? - proxy_username node['yum']['mysql57-community']['proxy_username'] unless node['yum']['mysql57-community']['proxy_username'].nil? - proxy_password node['yum']['mysql57-community']['proxy_password'] unless node['yum']['mysql57-community']['proxy_password'].nil? - repositoryid node['yum']['mysql57-community']['repositoryid'] unless node['yum']['mysql57-community']['repositoryid'].nil? - sslcacert node['yum']['mysql57-community']['sslcacert'] unless node['yum']['mysql57-community']['sslcacert'].nil? - sslclientcert node['yum']['mysql57-community']['sslclientcert'] unless node['yum']['mysql57-community']['sslclientcert'].nil? - sslclientkey node['yum']['mysql57-community']['sslclientkey'] unless node['yum']['mysql57-community']['sslclientkey'].nil? - sslverify node['yum']['mysql57-community']['sslverify'] unless node['yum']['mysql57-community']['sslverify'].nil? - timeout node['yum']['mysql57-community']['timeout'] unless node['yum']['mysql57-community']['timeout'].nil? - action :create -end diff --git a/cookbooks/yum/.foodcritic b/cookbooks/yum/.foodcritic deleted file mode 100644 index b9f8767..0000000 --- a/cookbooks/yum/.foodcritic +++ /dev/null @@ -1 +0,0 @@ -~FC016 diff --git a/cookbooks/yum/CHANGELOG.md b/cookbooks/yum/CHANGELOG.md index 045b197..d49c48a 100644 --- a/cookbooks/yum/CHANGELOG.md +++ b/cookbooks/yum/CHANGELOG.md @@ -2,31 +2,6 @@ This file is used to list changes made in each version of the yum cookbook. -## 5.0.0 (2017-02-12) - -### Breaking changes - -- Removed the yum_repository resource and instead require chef-client 12.14 or later, which has the yum repository functionality built in. This resolves Chef 13 compatibility warnings for any cookbook with the yum cookbook. - -### Other changes - -- Convert yum_globalconfig from an LWRP to a custom resource - -## 4.2.0 (2017-02-12) - -- Make cache in the DNF compat recipe -- Fix `fastestmirror_enabled`. -- Require Chef 12.1 not 12.0 -- Convert to Inspec - -## 4.1.0 (2016-10-21) - -- Purge yum cache before removing a repo not after - -## 4.0.0 (2016-09-06) - -- Remove support for Chef 11 - ## 3.13.0 (2016-09-06) - Add deprecation warning for add/remove actions, which were replaced with create/delete in Yum 3.0 diff --git a/cookbooks/yum/MAINTAINERS.md b/cookbooks/yum/MAINTAINERS.md index b3548a4..c6a51ae 100644 --- a/cookbooks/yum/MAINTAINERS.md +++ b/cookbooks/yum/MAINTAINERS.md @@ -1,10 +1,13 @@ # Maintainers +This file lists how this cookbook project is maintained. When making changes to the system, this +file tells you who needs to review your patch - you need a simple majority of maintainers +for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need +to not receive a veto from a Lieutenant or the Project Lead. -This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. - -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. +Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) +for details on the process and how to become a maintainer or the project lead. # Project Maintainer * [Tim Smith](https://github.com/tas50) diff --git a/cookbooks/yum/README.md b/cookbooks/yum/README.md index a312325..b73c3de 100644 --- a/cookbooks/yum/README.md +++ b/cookbooks/yum/README.md @@ -1,28 +1,92 @@ # yum Cookbook - [![Build Status](https://travis-ci.org/chef-cookbooks/yum.svg?branch=master)](http://travis-ci.org/chef-cookbooks/yum) [![Cookbook Version](https://img.shields.io/cookbook/v/yum.svg)](https://supermarket.chef.io/cookbooks/yum) -The Yum cookbook exposes the `yum_globalconfig` resource which allows a user to control global yum behavior. This resources aims to allow the user to configure all options listed in the `yum.conf` man page, found at +The Yum cookbook exposes the `yum_globalconfig` and `yum_repository` resources that allows a user to both control global behavior and make individual Yum repositories available for use. These resources aim to allow the user to configure all options listed in the `yum.conf` man page, found at [http://linux.die.net/man/5/yum.conf](http://linux.die.net/man/5/yum.conf) ## Requirements - ### Platforms - - RHEL/CentOS and derivatives - Fedora ### Chef - -- Chef 12.14+ +- Chef 11+ ### Cookbooks - - none -## Resources +## Resources/Providers +### yum_repository +This resource manages a yum repository configuration file at /etc/yum.repos.d/`repositoryid`.repo. When the file needs to be repaired, it calls yum-makecache so packages in the repo become available to the next resource. + +#### Example + +```ruby +# add the Zenoss repository +yum_repository 'zenoss' do + description "Zenoss Stable repo" + baseurl "http://dev.zenoss.com/yum/stable/" + gpgkey 'http://dev.zenoss.com/yum/RPM-GPG-KEY-zenoss' + action :create +end + +# add some internal company repo +yum_repository 'OurCo' do + description 'OurCo yum repository' + mirrorlist 'http://artifacts.ourco.org/mirrorlist?repo=ourco-6&arch=$basearch' + gpgkey 'http://artifacts.ourco.org/pub/yum/RPM-GPG-KEY-OURCO-6' + action :create +end +``` + +```ruby +# delete CentOS-Media repo +yum_repository 'CentOS-Media' do + action :delete +end +``` + +#### Actions +- `:create` - creates a repository file and builds the repository listing +- `:delete` - deletes the repository file +- `:makecache` - update yum cache + +#### Parameters +- `baseurl` - Must be a URL to the directory where the yum repository's 'repodata' directory lives. Can be an http://, ftp:// or file:// URL. You can specify multiple URLs in one baseurl statement. +- `cost` - relative cost of accessing this repository. Useful for weighing one repo's packages as greater/less than any other. defaults to 1000 +- `clean_metadata` - Run "yum clean metadata " during repository creation. defaults to true. +- `description` - Maps to the 'name' parameter in a repository .conf. Descriptive name for the repository channel. This directive must be specified. +- `enabled` - Either `true` or `false`. This tells yum whether or not use this repository. +- `enablegroups` - Either `true` or `false`. Determines whether yum will allow the use of package groups for this repository. Default is `true` (package groups are allowed). +- `exclude` - List of packages to exclude from updates or installs. This should be a space separated list in a single string. Shell globs using wildcards (eg. * and ?) are allowed. +- `failovermethod` - Either 'roundrobin' or 'priority'. +- `fastestmirror_enabled` - Either `true` or `false` +- `gpgcheck` - Either `true` or `false`. This tells yum whether or not it should perform a GPG signature check on packages. When this is set in the [main] section it sets the default for all repositories. The default is `true`. +- `gpgkey` - A URL pointing to the ASCII-armored GPG key file for the repository. This option is used if yum needs a public key to verify a package and the required key hasn't been imported into the RPM database. If this option is set, yum will automatically import the key from the specified URL. +- `http_caching` - Either 'all', 'packages', or 'none'. Determines how upstream HTTP caches are instructed to handle any HTTP downloads that Yum does. Defaults to 'all' +- `includepkgs` - Inverse of exclude. This is a list of packages you want to use from a repository. If this option lists only one package then that is all yum will ever see from the repository. Defaults to an empty list. +- `keepalive` - Either `true` or `false`. This tells yum whether or not HTTP/1.1 keepalive should be used with this repository. +- `make_cache` - Optional, Default is `true`, if `false` then `yum -q makecache` will not be ran +- `max_retries` - Set the number of times any attempt to retrieve a file should retry before returning an error. Setting this to '0' makes yum try forever. Default is '10'. +- `metadata_expire` - Time (in seconds) after which the metadata will expire. So that if the current metadata downloaded is less than this many seconds old then yum will not update the metadata against the repository. If you find that yum is not downloading information on updates as often as you would like lower the value of this option. You can also change from the default of using seconds to using days, hours or minutes by appending a d, h or m respectively. The default is 6 hours, to compliment yum-updatesd running once an hour. It's also possible to use the word "never", meaning that the metadata will never expire. Note that when using a metalink file the metalink must always be newer than the metadata for the repository, due to the validation, so this timeout also applies to the metalink file. +- `mirrorlist` - Specifies a URL to a file containing a list of baseurls. This can be used instead of or with the baseurl option. Substitution variables, described below, can be used with this option. As a special hack is the mirrorlist URL contains the word "metalink" then the value of mirrorlist is copied to metalink (if metalink is not set) +- `mirror_expire` - Time (in seconds) after which the mirrorlist locally cached will expire. If the current mirrorlist is less than this many seconds old then yum will not download another copy of the mirrorlist, it has the same extra format as metadata_expire. If you find that yum is not downloading the mirrorlists as often as you would like lower the value of this option. +- `mirrorlist_expire` - alias for mirror_expire +- `mode` - Permissions mode of .repo file on disk. Useful for scenarios where secrets are in the repo file. If set to '600', normal users will not be able to use yum search, yum info, etc. Defaults to '0644' +- `priority` - When the yum-priorities plug-in is enabled, you set priorities on repository entries, where N is an integer from 1 to 99. The default priority for repositories is 99. +- `proxy` - URL to the proxy server that yum should use. +- `proxy_username` - username to use for proxy +- `proxy_password` - password for this proxy +- `report_instanceid` - Report instance ID when using Amazon Linux AMIs and repositories +- `repositoryid` - Must be a unique name for each repository, one word. Defaults to name attribute. +- `sensitive` - Optional, Default is `false`, if `true` then content of repository file is hidden from chef run output. +- `source` - Use a custom template source instead of the default one in the yum cookbook +- `sslcacert` - Path to the directory containing the databases of the certificate authorities yum should use to verify SSL certificates. Defaults to none - uses system default +- `sslclientcert` - Path to the SSL client certificate yum should use to connect to repos/remote sites Defaults to none. +- `sslclientkey` - Path to the SSL client key yum should use to connect to repos/remote sites Defaults to none. +- `sslverify` - Either `true` or `false`. Determines if yum will verify SSL certificates/hosts. Defaults to `true` +- `timeout` - Number of seconds to wait for a connection before timing out. Defaults to 30 seconds. This may be too short of a time for extremely overloaded sites. ### yum_globalconfig - This renders a template with global yum configuration parameters. The default recipe uses it to render `/etc/yum.conf`. It is flexible enough to be used in other scenarios, such as building RPMs in isolation by modifying `installroot`. #### Example @@ -37,30 +101,22 @@ yum_globalconfig '/my/chroot/etc/yum.conf' do end ``` -#### Properties - -`yum_globalconfig` can take most of the same parameters as a `yum_repository`, plus more, too numerous to describe here. Below are a few of the more commonly used ones. For a complete list, please consult the `yum.conf` man page, found here: - +#### Parameters +`yum_globalconfig` can take most of the same parameters as a `yum_repository`, plus more, too numerous to describe here. Below are a few of the more commonly used ones. For a complete list, please consult the `yum.conf` man page, found here: [http://linux.die.net/man/5/yum.conf](http://linux.die.net/man/5/yum.conf) - `cachedir` - Directory where yum should store its cache and db files. The default is '/var/cache/yum'. - `keepcache` - Either `true` or `false`. Determines whether or not yum keeps the cache of headers and packages after successful installation. Default is `false` -- `debuglevel` - Debug message output level. Practical range is 0-10\. Default is '2'. +- `debuglevel` - Debug message output level. Practical range is 0-10. Default is '2'. - `exclude` - List of packages to exclude from updates or installs. This should be a space separated list. Shell globs using wildcards (eg. * and ?) are allowed. - `installonlypkgs` = List of package provides that should only ever be installed, never updated. Kernels in particular fall into this category. Defaults to kernel, kernel-bigmem, kernel-enterprise, kernel-smp, kernel-debug, kernel-unsupported, kernel-source, kernel-devel, kernel-PAE, kernel-PAE-debug. - `logfile` - Full directory and file name for where yum should write its log file. -- `exactarch` - Either `true` or `false`. Set to `true` to make 'yum update' only update the architectures of packages that you have installed. ie: with this enabled yum will not install an i686 package to update an x86_64 package. Default is `true` +- `exactarch` - Either `true` or `false`. Set to `true` to make 'yum update' only update the architectures of packages that you have installed. ie: with this enabled yum will not install an i686 package to update an x86_64 package. Default is `true` - `gpgcheck` - Either `true` or `false`. This tells yum whether or not it should perform a GPG signature check on the packages gotten from this repository. -### yum_repository - -This resource is now provided by chef-client 12.14 and later and has been removed from this cookbook. If you require this resource we highly recommend upgrading your chef-client, but if that is not an option you can pin the 4.X yum cookbook. - ## Recipes - - `default` - Configures `yum_globalconfig[/etc/yum.conf]` with values found in node attributes at `node['yum']['main']` -- `dnf_yum_compat` - Installs the yum package using dnf on Fedora systems to provide support for the package resource in recipes. This is necessary on chef-client < 12.18\. This recipe should be 1st on a Fedora runlist +- `dnf_yum_compat` - Installs the yum package using dnf on Fedora systems to provide support for the package resource in recipes. This is necessary as Chef does not yet (as of Q4 2015) have native support for DNF. This recipe should be 1st on a Fedora runlist ## Attributes - The following attributes are set by default ```ruby @@ -76,16 +132,14 @@ default['yum']['main']['installonlypkgs'] = nil default['yum']['main']['installroot'] = nil ``` -For Amazon platform nodes, +For Amazon platform nodes, ```ruby default['yum']['main']['releasever'] = 'latest' ``` ## Related Cookbooks - Recipes from older versions of this cookbook have been moved individual cookbooks. Recipes for managing platform yum configurations and installing specific repositories can be found in one (or more!) of the following cookbook. - - yum-centos - yum-fedora - yum-amazon @@ -97,11 +151,9 @@ Recipes from older versions of this cookbook have been moved individual cookbook - yum-pgdg ## Usage - Put `depends 'yum'` in your metadata.rb to gain access to the yum_repository resource. ## License & Authors - - Author:: Eric G. Wolfe - Author:: Matt Ray ([matt@chef.io](mailto:matt@chef.io)) - Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io)) @@ -109,7 +161,7 @@ Put `depends 'yum'` in your metadata.rb to gain access to the yum_repository res ```text Copyright:: 2011 Eric G. Wolfe -Copyright:: 2013-2017 Chef Software, Inc. +Copyright:: 2013-2016 Chef Software, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cookbooks/yum/libraries/matchers.rb b/cookbooks/yum/libraries/matchers.rb index 220238a..631b708 100644 --- a/cookbooks/yum/libraries/matchers.rb +++ b/cookbooks/yum/libraries/matchers.rb @@ -1,4 +1,20 @@ if defined?(ChefSpec) + def create_yum_repository(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:yum_repository, :create, resource_name) + end + + def add_yum_repository(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:yum_repository, :add, resource_name) + end + + def delete_yum_repository(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:yum_repository, :delete, resource_name) + end + + def remove_yum_repository(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:yum_repository, :remove, resource_name) + end + def create_yum_globalconfig(resource_name) ChefSpec::Matchers::ResourceMatcher.new(:yum_globalconfig, :create, resource_name) end diff --git a/cookbooks/yum/metadata.json b/cookbooks/yum/metadata.json index 550e2ab..3b3faac 100644 --- a/cookbooks/yum/metadata.json +++ b/cookbooks/yum/metadata.json @@ -1 +1 @@ -{"name":"yum","version":"5.0.0","description":"Configures various yum components on Red Hat-like systems","long_description":"","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","zlinux":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file +{"name":"yum","version":"3.13.0","description":"Configures various yum components on Red Hat-like systems","long_description":"","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"amazon":">= 0.0.0","centos":">= 0.0.0","fedora":">= 0.0.0","oracle":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","zlinux":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}} \ No newline at end of file diff --git a/cookbooks/yum/providers/globalconfig.rb b/cookbooks/yum/providers/globalconfig.rb new file mode 100644 index 0000000..ef649bb --- /dev/null +++ b/cookbooks/yum/providers/globalconfig.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: yum +# Provider:: repository +# +# Author:: Sean OMeara +# Copyright 2013-2016, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +use_inline_resources + +def whyrun_supported? + true +end + +action :create do + template new_resource.path do + source 'main.erb' + cookbook 'yum' + mode '0644' + variables(config: new_resource) + end +end + +action :delete do + file new_resource.path do + action :delete + end +end diff --git a/cookbooks/yum/providers/repository.rb b/cookbooks/yum/providers/repository.rb new file mode 100644 index 0000000..0b7846c --- /dev/null +++ b/cookbooks/yum/providers/repository.rb @@ -0,0 +1,115 @@ +# +# Cookbook Name:: yum +# Provider:: repository +# +# Author:: Sean OMeara +# Copyright 2013-2016, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# In Chef 11 and above, calling the use_inline_resources method will +# make Chef create a new "run_context". When an action is called, any +# nested resources are compiled and converged in isolation from the +# recipe that calls it. + +use_inline_resources + +def whyrun_supported? + true +end + +action :add do + Chef::Log.warn('The :add method in yum_repository has been deprecated in favor of :create. Please update your cookbook to use the :create action') + action_create +end + +action :remove do + Chef::Log.warn('The :remove method in yum_repository has been deprecated in favor of :delete. Repository deletion in Chef 12.14+ with :remove will fail') + action_delete +end + +action :create do + if new_resource.clean_headers + Chef::Log.warn <<-eos + Use of `clean_headers` in resource yum[#{new_resource.repositoryid}] is now deprecated and will be removed in a future release. + `clean_metadata` should be used instead + eos + end + + template "/etc/yum.repos.d/#{new_resource.repositoryid}.repo" do + if new_resource.source.nil? + source 'repo.erb' + cookbook 'yum' + else + source new_resource.source + end + mode new_resource.mode + sensitive new_resource.sensitive + variables(config: new_resource) + if new_resource.make_cache + notifies :run, "execute[yum clean metadata #{new_resource.repositoryid}]", :immediately if new_resource.clean_metadata || new_resource.clean_headers + notifies :run, "execute[yum-makecache-#{new_resource.repositoryid}]", :immediately + notifies :create, "ruby_block[yum-cache-reload-#{new_resource.repositoryid}]", :immediately + end + end + + execute "yum clean metadata #{new_resource.repositoryid}" do + command "yum clean metadata --disablerepo=* --enablerepo=#{new_resource.repositoryid}" + action :nothing + end + + # get the metadata for this repo only + execute "yum-makecache-#{new_resource.repositoryid}" do + command "yum -q -y makecache --disablerepo=* --enablerepo=#{new_resource.repositoryid}" + action :nothing + only_if { new_resource.enabled } + end + + # reload internal Chef yum cache + ruby_block "yum-cache-reload-#{new_resource.repositoryid}" do + block { Chef::Provider::Package::Yum::YumCache.instance.reload } + action :nothing + end +end + +action :delete do + file "/etc/yum.repos.d/#{new_resource.repositoryid}.repo" do + action :delete + notifies :run, "execute[yum clean all #{new_resource.repositoryid}]", :immediately + notifies :create, "ruby_block[yum-cache-reload-#{new_resource.repositoryid}]", :immediately + end + + execute "yum clean all #{new_resource.repositoryid}" do + command "yum clean all --disablerepo=* --enablerepo=#{new_resource.repositoryid}" + only_if "yum repolist | grep -P '^#{new_resource.repositoryid}([ \t]|$)'" + action :nothing + end + + ruby_block "yum-cache-reload-#{new_resource.repositoryid}" do + block { Chef::Provider::Package::Yum::YumCache.instance.reload } + action :nothing + end +end + +action :makecache do + execute "yum-makecache-#{new_resource.repositoryid}" do + command "yum -q makecache --disablerepo=* --enablerepo=#{new_resource.repositoryid}" + action :run + end + + ruby_block "yum-cache-reload-#{new_resource.repositoryid}" do + block { Chef::Provider::Package::Yum::YumCache.instance.reload } + action :run + end +end diff --git a/cookbooks/yum/recipes/default.rb b/cookbooks/yum/recipes/default.rb index 2270028..d1fe392 100644 --- a/cookbooks/yum/recipes/default.rb +++ b/cookbooks/yum/recipes/default.rb @@ -3,7 +3,7 @@ # Author:: Joshua Timberman () # Recipe:: yum::default # -# Copyright:: 2013-2016, Chef Software, Inc () +# Copyright 2013-2016, Chef Software, Inc () # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/yum/recipes/dnf_yum_compat.rb b/cookbooks/yum/recipes/dnf_yum_compat.rb index f217cb7..a673f17 100644 --- a/cookbooks/yum/recipes/dnf_yum_compat.rb +++ b/cookbooks/yum/recipes/dnf_yum_compat.rb @@ -2,7 +2,7 @@ # Author:: Tim Smith () # Recipe:: yum::fedora_yum_compat # -# Copyright:: 2015-2016, Chef Software, Inc () +# Copyright 2015-2016, Chef Software, Inc () # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,14 +16,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -execute 'make yum cache' do - command 'yum makecache' - action :nothing -end - execute 'install yum' do command 'dnf install yum -y' not_if { ::File.exist?('/var/lib/yum') } action :nothing - notifies :run, 'execute[make yum cache]', :immediately end.run_action(:run) diff --git a/cookbooks/yum/resources/globalconfig.rb b/cookbooks/yum/resources/globalconfig.rb index a452e4c..e30185b 100644 --- a/cookbooks/yum/resources/globalconfig.rb +++ b/cookbooks/yum/resources/globalconfig.rb @@ -1,9 +1,9 @@ # -# Cookbook:: yum +# Cookbook Name:: yum # Resource:: repository # # Author:: Sean OMeara -# Copyright:: 2013-2017, Chef Software, Inc. +# Copyright 2013-2016, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,102 +18,92 @@ # limitations under the License. # +actions :create, :delete + +default_action :create + # http://linux.die.net/man/5/yum.conf -property :alwaysprompt, [TrueClass, FalseClass] -property :assumeyes, [TrueClass, FalseClass] -property :bandwidth, String, regex: /^\d+/ -property :bugtracker_url, String, regex: /.*/ -property :clean_requirements_on_remove, [TrueClass, FalseClass] -property :cachedir, String, regex: /.*/, default: '/var/cache/yum/$basearch/$releasever' -property :color, String, equal_to: %w(always never) -property :color_list_available_downgrade, String, regex: /.*/ -property :color_list_available_install, String, regex: /.*/ -property :color_list_available_reinstall, String, regex: /.*/ -property :color_list_available_upgrade, String, regex: /.*/ -property :color_list_installed_extra, String, regex: /.*/ -property :color_list_installed_newer, String, regex: /.*/ -property :color_list_installed_older, String, regex: /.*/ -property :color_list_installed_reinstall, String, regex: /.*/ -property :color_search_match, String, regex: /.*/ -property :color_update_installed, String, regex: /.*/ -property :color_update_local, String, regex: /.*/ -property :color_update_remote, String, regex: /.*/ -property :commands, String, regex: /.*/ -property :debuglevel, String, regex: /^\d+$/, default: '2' -property :deltarpm, [TrueClass, FalseClass] -property :diskspacecheck, [TrueClass, FalseClass] -property :distroverpkg, String, regex: /.*/ -property :enable_group_conditionals, [TrueClass, FalseClass] -property :errorlevel, String, regex: /^\d+$/ -property :exactarch, [TrueClass, FalseClass], default: true -property :exclude, String, regex: /.*/ -property :gpgcheck, [TrueClass, FalseClass], default: true -property :group_package_types, String, regex: /.*/ -property :groupremove_leaf_only, [TrueClass, FalseClass] -property :history_list_view, String, equal_to: %w(users commands single-user-commands) -property :history_record, [TrueClass, FalseClass] -property :history_record_packages, String, regex: /.*/ -property :http_caching, String, equal_to: %w(packages all none) -property :installonly_limit, String, regex: [/^\d+/, /keep/], default: '3' -property :installonlypkgs, String, regex: /.*/ -property :installroot, String, regex: /.*/ -property :keepalive, [TrueClass, FalseClass] -property :keepcache, [TrueClass, FalseClass], default: false -property :kernelpkgnames, String, regex: /.*/ -property :localpkg_gpgcheck, [TrueClass, FalseClass] -property :logfile, String, regex: /.*/, default: '/var/log/yum.log' -property :max_retries, String, regex: /^\d+$/ -property :mdpolicy, String, equal_to: %w(instant group:primary group:small group:main group:all) -property :metadata_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/] -property :mirrorlist_expire, String, regex: /^\d+$/ -property :multilib_policy, String, equal_to: %w(all best) -property :obsoletes, [TrueClass, FalseClass] -property :overwrite_groups, [TrueClass, FalseClass] -property :password, String, regex: /.*/ -property :path, String, regex: /.*/, name_property: true -property :persistdir, String, regex: /.*/ -property :pluginconfpath, String, regex: /.*/ -property :pluginpath, String, regex: /.*/ -property :plugins, [TrueClass, FalseClass], default: true -property :protected_multilib, [TrueClass, FalseClass] -property :protected_packages, String, regex: /.*/ -property :proxy, String, regex: /.*/ -property :proxy_password, String, regex: /.*/ -property :proxy_username, String, regex: /.*/ -property :recent, String, regex: /^\d+$/ -property :releasever, String, regex: /.*/ -property :repo_gpgcheck, [TrueClass, FalseClass] -property :reposdir, String, regex: /.*/ -property :reset_nice, [TrueClass, FalseClass] -property :rpmverbosity, String, equal_to: %w(info critical emergency error warn debug) -property :showdupesfromrepos, [TrueClass, FalseClass] -property :skip_broken, [TrueClass, FalseClass] -property :ssl_check_cert_permissions, [TrueClass, FalseClass] -property :sslcacert, String, regex: /.*/ -property :sslclientcert, String, regex: /.*/ -property :sslclientkey, String, regex: /.*/ -property :sslverify, [TrueClass, FalseClass] -property :syslog_device, String, regex: /.*/ -property :syslog_facility, String, regex: /.*/ -property :syslog_ident, String, regex: /.*/ -property :throttle, String, regex: [/\d+k/, /\d+M/, /\d+G/] -property :timeout, String, regex: /^\d+$/ -property :tolerant, [TrueClass, FalseClass] -property :tsflags, String, regex: /.*/ -property :username, String, regex: /.*/ -property :options, Hash +attribute :alwaysprompt, kind_of: [TrueClass, FalseClass], default: nil +attribute :assumeyes, kind_of: [TrueClass, FalseClass], default: nil +attribute :bandwidth, kind_of: String, regex: /^\d+/, default: nil +attribute :bugtracker_url, kind_of: String, regex: /.*/, default: nil +attribute :clean_requirements_on_remove, kind_of: [TrueClass, FalseClass], default: nil +attribute :cachedir, kind_of: String, regex: /.*/, default: '/var/cache/yum/$basearch/$releasever' +attribute :color, kind_of: String, equal_to: %w(always never), default: nil +attribute :color_list_available_downgrade, kind_of: String, regex: /.*/, default: nil +attribute :color_list_available_install, kind_of: String, regex: /.*/, default: nil +attribute :color_list_available_reinstall, kind_of: String, regex: /.*/, default: nil +attribute :color_list_available_upgrade, kind_of: String, regex: /.*/, default: nil +attribute :color_list_installed_extra, kind_of: String, regex: /.*/, default: nil +attribute :color_list_installed_newer, kind_of: String, regex: /.*/, default: nil +attribute :color_list_installed_older, kind_of: String, regex: /.*/, default: nil +attribute :color_list_installed_reinstall, kind_of: String, regex: /.*/, default: nil +attribute :color_search_match, kind_of: String, regex: /.*/, default: nil +attribute :color_update_installed, kind_of: String, regex: /.*/, default: nil +attribute :color_update_local, kind_of: String, regex: /.*/, default: nil +attribute :color_update_remote, kind_of: String, regex: /.*/, default: nil +attribute :commands, kind_of: String, regex: /.*/, default: nil +attribute :debuglevel, kind_of: String, regex: /^\d+$/, default: '2' +attribute :deltarpm, kind_of: [TrueClass, FalseClass], default: nil +attribute :diskspacecheck, kind_of: [TrueClass, FalseClass], default: nil +attribute :distroverpkg, kind_of: String, regex: /.*/, default: nil +attribute :enable_group_conditionals, kind_of: [TrueClass, FalseClass], default: nil +attribute :errorlevel, kind_of: String, regex: /^\d+$/, default: nil +attribute :exactarch, kind_of: [TrueClass, FalseClass], default: true +attribute :exclude, kind_of: String, regex: /.*/, default: nil +attribute :gpgcheck, kind_of: [TrueClass, FalseClass], default: true +attribute :group_package_types, kind_of: String, regex: /.*/, default: nil +attribute :groupremove_leaf_only, kind_of: [TrueClass, FalseClass], default: nil +attribute :history_list_view, kind_of: String, equal_to: %w(users commands single-user-commands), default: nil +attribute :history_record, kind_of: [TrueClass, FalseClass], default: nil +attribute :history_record_packages, kind_of: String, regex: /.*/, default: nil +attribute :http_caching, kind_of: String, equal_to: %w(packages all none), default: nil +attribute :installonly_limit, kind_of: String, regex: [/^\d+/, /keep/], default: '3' +attribute :installonlypkgs, kind_of: String, regex: /.*/, default: nil +attribute :installroot, kind_of: String, regex: /.*/, default: nil +attribute :keepalive, kind_of: [TrueClass, FalseClass], default: nil +attribute :keepcache, kind_of: [TrueClass, FalseClass], default: false +attribute :kernelpkgnames, kind_of: String, regex: /.*/, default: nil +attribute :localpkg_gpgcheck, kind_of: [TrueClass, FalseClass], default: nil +attribute :logfile, kind_of: String, regex: /.*/, default: '/var/log/yum.log' +attribute :max_retries, kind_of: String, regex: /^\d+$/, default: nil +attribute :mdpolicy, kind_of: String, equal_to: %w(instant group:primary group:small group:main group:all), default: nil +attribute :metadata_expire, kind_of: String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/], default: nil +attribute :mirrorlist_expire, kind_of: String, regex: /^\d+$/, default: nil +attribute :multilib_policy, kind_of: String, equal_to: %w(all best), default: nil +attribute :obsoletes, kind_of: [TrueClass, FalseClass], default: nil +attribute :overwrite_groups, kind_of: [TrueClass, FalseClass], default: nil +attribute :password, kind_of: String, regex: /.*/, default: nil +attribute :path, kind_of: String, regex: /.*/, name_attribute: true +attribute :persistdir, kind_of: String, regex: /.*/, default: nil +attribute :pluginconfpath, kind_of: String, regex: /.*/, default: nil +attribute :pluginpath, kind_of: String, regex: /.*/, default: nil +attribute :plugins, kind_of: [TrueClass, FalseClass], default: true +attribute :protected_multilib, kind_of: [TrueClass, FalseClass], default: nil +attribute :protected_packages, kind_of: String, regex: /.*/, default: nil +attribute :proxy, kind_of: String, regex: /.*/, default: nil +attribute :proxy_password, kind_of: String, regex: /.*/, default: nil +attribute :proxy_username, kind_of: String, regex: /.*/, default: nil +attribute :recent, kind_of: String, regex: /^\d+$/, default: nil +attribute :releasever, kind_of: String, regex: /.*/, default: nil +attribute :repo_gpgcheck, kind_of: [TrueClass, FalseClass], default: nil +attribute :reposdir, kind_of: String, regex: /.*/, default: nil +attribute :reset_nice, kind_of: [TrueClass, FalseClass], default: nil +attribute :rpmverbosity, kind_of: String, equal_to: %w(info critical emergency error warn debug), default: nil +attribute :showdupesfromrepos, kind_of: [TrueClass, FalseClass], default: nil +attribute :skip_broken, kind_of: [TrueClass, FalseClass], default: nil +attribute :ssl_check_cert_permissions, kind_of: [TrueClass, FalseClass], default: nil +attribute :sslcacert, kind_of: String, regex: /.*/, default: nil +attribute :sslclientcert, kind_of: String, regex: /.*/, default: nil +attribute :sslclientkey, kind_of: String, regex: /.*/, default: nil +attribute :sslverify, kind_of: [TrueClass, FalseClass], default: nil +attribute :syslog_device, kind_of: String, regex: /.*/, default: nil +attribute :syslog_facility, kind_of: String, regex: /.*/, default: nil +attribute :syslog_ident, kind_of: String, regex: /.*/, default: nil +attribute :throttle, kind_of: String, regex: [/\d+k/, /\d+M/, /\d+G/], default: nil +attribute :timeout, kind_of: String, regex: /^\d+$/, default: nil +attribute :tolerant, kind_of: [TrueClass, FalseClass], default: nil +attribute :tsflags, kind_of: String, regex: /.*/, default: nil +attribute :username, kind_of: String, regex: /.*/, default: nil -action :create do - template new_resource.path do - source 'main.erb' - cookbook 'yum' - mode '0644' - variables(config: new_resource) - end -end - -action :delete do - file new_resource.path do - action :delete - end -end +attribute :options, kind_of: Hash diff --git a/cookbooks/yum/resources/repository.rb b/cookbooks/yum/resources/repository.rb new file mode 100644 index 0000000..7514d5a --- /dev/null +++ b/cookbooks/yum/resources/repository.rb @@ -0,0 +1,71 @@ +# +# Cookbook Name:: yum +# Resource:: repository +# +# Author:: Sean OMeara +# Copyright 2013-2016, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :create, :delete, :add, :remove, :makecache + +default_action :create + +# http://linux.die.net/man/5/yum.conf +attribute :baseurl, kind_of: [String, Array], regex: /.*/, default: nil +attribute :cost, kind_of: String, regex: /^\d+$/, default: nil +attribute :clean_headers, kind_of: [TrueClass, FalseClass], default: false # deprecated +attribute :clean_metadata, kind_of: [TrueClass, FalseClass], default: true +attribute :description, kind_of: String, regex: /.*/, default: 'Ye Ole Rpm Repo' +attribute :enabled, kind_of: [TrueClass, FalseClass], default: true +attribute :enablegroups, kind_of: [TrueClass, FalseClass], default: nil +attribute :exclude, kind_of: String, regex: /.*/, default: nil +attribute :failovermethod, kind_of: String, equal_to: %w(priority roundrobin), default: nil +attribute :fastestmirror_enabled, kind_of: [TrueClass, FalseClass], default: nil +attribute :gpgcheck, kind_of: [TrueClass, FalseClass], default: true +attribute :gpgkey, kind_of: [String, Array], regex: /.*/, default: nil +attribute :http_caching, kind_of: String, equal_to: %w(packages all none), default: nil +attribute :include_config, kind_of: String, regex: /.*/, default: nil +attribute :includepkgs, kind_of: String, regex: /.*/, default: nil +attribute :keepalive, kind_of: [TrueClass, FalseClass], default: nil +attribute :make_cache, kind_of: [TrueClass, FalseClass], default: true +attribute :max_retries, kind_of: [String, Integer], default: nil +attribute :metadata_expire, kind_of: String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/], default: nil +attribute :mirrorexpire, kind_of: String, regex: /.*/, default: nil +attribute :mirrorlist, kind_of: String, regex: /.*/, default: nil +attribute :mirror_expire, kind_of: String, regex: [/^\d+$/, /^\d+[mhd]$/], default: nil +attribute :mirrorlist_expire, kind_of: String, regex: [/^\d+$/, /^\d+[mhd]$/], default: nil +attribute :mode, default: '0644' +attribute :priority, kind_of: String, regex: /^(\d?[0-9]|[0-9][0-9])$/, default: nil +attribute :proxy, kind_of: String, regex: /.*/, default: nil +attribute :proxy_username, kind_of: String, regex: /.*/, default: nil +attribute :proxy_password, kind_of: String, regex: /.*/, default: nil +attribute :username, kind_of: String, regex: /.*/, default: nil +attribute :password, kind_of: String, regex: /.*/, default: nil +attribute :repo_gpgcheck, kind_of: [TrueClass, FalseClass], default: nil +attribute :report_instanceid, kind_of: [TrueClass, FalseClass], default: nil +attribute :repositoryid, kind_of: String, regex: /.*/, name_attribute: true +attribute :sensitive, kind_of: [TrueClass, FalseClass], default: false +attribute :skip_if_unavailable, kind_of: [TrueClass, FalseClass], default: nil +attribute :source, kind_of: String, regex: /.*/, default: nil +attribute :sslcacert, kind_of: String, regex: /.*/, default: nil +attribute :sslclientcert, kind_of: String, regex: /.*/, default: nil +attribute :sslclientkey, kind_of: String, regex: /.*/, default: nil +attribute :sslverify, kind_of: [TrueClass, FalseClass], default: nil +attribute :timeout, kind_of: String, regex: /^\d+$/, default: nil + +attribute :options, kind_of: Hash + +alias_method :url, :baseurl +alias_method :keyurl, :gpgkey diff --git a/cookbooks/yum/templates/main.erb b/cookbooks/yum/templates/default/main.erb similarity index 100% rename from cookbooks/yum/templates/main.erb rename to cookbooks/yum/templates/default/main.erb diff --git a/cookbooks/yum/templates/default/repo.erb b/cookbooks/yum/templates/default/repo.erb new file mode 100644 index 0000000..5fd6e7f --- /dev/null +++ b/cookbooks/yum/templates/default/repo.erb @@ -0,0 +1,130 @@ +# This file was generated by Chef +# Do NOT modify this file by hand. + +[<%= @config.repositoryid %>] +name=<%= @config.description %> +<% if @config.baseurl %> +baseurl=<%= case @config.baseurl + when Array + @config.baseurl.join("\n") + else + @config.baseurl + end %> +<% end -%> +<% if @config.cost %> +cost=<%= @config.cost %> +<% end %> +<% if @config.enabled %> +enabled=1 +<% else %> +enabled=0 +<% end %> +<% if @config.enablegroups %> +enablegroups=1 +<% end %> +<% if @config.exclude %> +exclude=<%= @config.exclude %> +<% end %> +<% if @config.failovermethod %> +failovermethod=<%= @config.failovermethod %> +<% end %> +<% if @config.fastestmirror_enabled %> +fastestmirror_enabled=<%= @config.fastestmirror_enabled %> +<% end %> +<% if @config.gpgcheck %> +gpgcheck=1 +<% else %> +gpgcheck=0 +<% end %> +<% if @config.gpgkey %> +gpgkey=<%= case @config.gpgkey + when Array + @config.gpgkey.join("\n ") + else + @config.gpgkey + end %> +<% end -%> +<% if @config.http_caching %> +http_caching=<%= @config.http_caching %> +<% end %> +<% if @config.include_config %> +include=<%= @config.include_config %> +<% end %> +<% if @config.includepkgs %> +includepkgs=<%= @config.includepkgs %> +<% end %> +<% if @config.keepalive %> +keepalive=1 +<% end %> +<% if @config.metadata_expire %> +metadata_expire=<%= @config.metadata_expire %> +<% end %> +<% if @config.mirrorlist %> +mirrorlist=<%= @config.mirrorlist %> +<% end %> +<% if @config.mirror_expire %> +mirror_expire=<%= @config.mirror_expire %> +<% end %> +<% if @config.mirrorlist_expire %> +mirrorlist_expire=<%= @config.mirrorlist_expire %> +<% end %> +<% if @config.priority %> +priority=<%= @config.priority %> +<% end %> +<% if @config.proxy %> +proxy=<%= @config.proxy %> +<% end %> +<% if @config.proxy_username %> +proxy_username=<%= @config.proxy_username %> +<% end %> +<% if @config.proxy_password %> +proxy_password=<%= @config.proxy_password %> +<% end %> +<% if @config.username %> +username=<%= @config.username %> +<% end %> +<% if @config.password %> +password=<%= @config.password %> +<% end %> +<% if @config.repo_gpgcheck %> +repo_gpgcheck=1 +<% end %> +<% if @config.max_retries %> +retries=<%= @config.max_retries %> +<% end %> +<% if @config.report_instanceid %> +report_instanceid=<%= @config.report_instanceid %> +<% end %> +<% if @config.skip_if_unavailable %> +skip_if_unavailable=1 +<% end %> +<% if @config.sslcacert %> +sslcacert=<%= @config.sslcacert %> +<% end %> +<% if @config.sslclientcert %> +sslclientcert=<%= @config.sslclientcert %> +<% end %> +<% if @config.sslclientkey %> +sslclientkey=<%= @config.sslclientkey %> +<% end %> +<% unless @config.sslverify.nil? %> +sslverify=<%= ( @config.sslverify ) ? 'true' : 'false' %> +<% end %> +<% if @config.timeout %> +timeout=<%= @config.timeout %> +<% end %> +<% if @config.options -%> +<% @config.options.each do |key, value| -%> +<%= key %>=<%= + case value + when Array + value.join("\n ") + when TrueClass + '1' + when FalseClass + '0' + else + value + end %> +<% end -%> +<% end -%> diff --git a/site-cookbooks/kosmos-base/metadata.rb b/site-cookbooks/kosmos-base/metadata.rb index 8e275f9..d59a182 100644 --- a/site-cookbooks/kosmos-base/metadata.rb +++ b/site-cookbooks/kosmos-base/metadata.rb @@ -6,7 +6,7 @@ description 'The Kosmos base cookbook' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '0.1.1' -depends 'unattended-upgrades' +depends 'apt' depends 'users' depends 'sudo' depends 'kosmos-postfix' @@ -14,3 +14,4 @@ depends 'hostname' depends 'firewall' depends 'chef_client_updater' depends 'timezone-ii' +depends 'ntp' diff --git a/site-cookbooks/kosmos-base/recipes/default.rb b/site-cookbooks/kosmos-base/recipes/default.rb index 2d88fa2..8b65e93 100644 --- a/site-cookbooks/kosmos-base/recipes/default.rb +++ b/site-cookbooks/kosmos-base/recipes/default.rb @@ -7,7 +7,9 @@ # All rights reserved - Do Not Redistribute # +include_recipe 'apt' include_recipe 'timezone-ii' +include_recipe 'ntp' # Update chef to the chosen version chef_version = '12.19.36' @@ -16,50 +18,51 @@ chef_client_updater "Install #{chef_version}" do end package 'mailutils' -node.override['unattended-upgrades']['admin_email'] = 'ops@5apps.com' -include_recipe 'unattended-upgrades' - package 'mosh' -# Searches data bag "users" for groups attribute "sysadmin". -# Places returned users in Unix group "sysadmin" with GID 2300. -users_manage 'sysadmin' do - group_id 2300 - action [:remove, :create] -end +# Don't create users and rewrite the sudo config in development environment. +# It breaks the vagrant user +unless node.chef_environment == "development" + # Searches data bag "users" for groups attribute "sysadmin". + # Places returned users in Unix group "sysadmin" with GID 2300. + users_manage 'sysadmin' do + group_id 2300 + action [:remove, :create] + end -node.override['authorization']['sudo']['sudoers_defaults'] = [ - # not default on Ubuntu, explicitely enable. Uses a minimal white list of - # environment variables - 'env_reset', - # Send emails on unauthorized attempts - 'mail_badpass', - 'secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"', -] -node.override['authorization']['sudo']['passwordless'] = true -include_recipe 'sudo' + node.override['authorization']['sudo']['sudoers_defaults'] = [ + # not default on Ubuntu, explicitely enable. Uses a minimal white list of + # environment variables + 'env_reset', + # Send emails on unauthorized attempts + 'mail_badpass', + 'secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"', + ] + node.override['authorization']['sudo']['passwordless'] = true + include_recipe 'sudo' -include_recipe 'kosmos-postfix' + include_recipe 'kosmos-base::firewall' -node.override['set_fqdn'] = '*' -include_recipe 'hostname' + include_recipe 'kosmos-postfix' -include_recipe 'kosmos-base::firewall' + node.override['set_fqdn'] = '*' + include_recipe 'hostname' -package 'ca-certificates' + package 'ca-certificates' -directory '/usr/local/share/ca-certificates/cacert' do - action :create -end + directory '/usr/local/share/ca-certificates/cacert' do + action :create + end -['http://www.cacert.org/certs/root.crt', 'http://www.cacert.org/certs/class3.crt'].each do |cert| - remote_file "/usr/local/share/ca-certificates/cacert/#{File.basename(cert)}" do - source cert - action :create_if_missing - notifies :run, 'execute[update-ca-certificates]', :immediately + ['http://www.cacert.org/certs/root.crt', 'http://www.cacert.org/certs/class3.crt'].each do |cert| + remote_file "/usr/local/share/ca-certificates/cacert/#{File.basename(cert)}" do + source cert + action :create_if_missing + notifies :run, 'execute[update-ca-certificates]', :immediately + end + end + + execute 'update-ca-certificates' do + action :nothing end end - -execute 'update-ca-certificates' do - action :nothing -end diff --git a/site-cookbooks/kosmos-mediawiki/metadata.rb b/site-cookbooks/kosmos-mediawiki/metadata.rb index 0df6188..5b654b0 100644 --- a/site-cookbooks/kosmos-mediawiki/metadata.rb +++ b/site-cookbooks/kosmos-mediawiki/metadata.rb @@ -9,3 +9,5 @@ version '0.1.0' depends "mediawiki" depends "ark" depends "backup" +depends "kosmos-nginx" +depends "kosmos-base" diff --git a/site-cookbooks/kosmos-mediawiki/recipes/default.rb b/site-cookbooks/kosmos-mediawiki/recipes/default.rb index 89630f2..98963d3 100644 --- a/site-cookbooks/kosmos-mediawiki/recipes/default.rb +++ b/site-cookbooks/kosmos-mediawiki/recipes/default.rb @@ -20,8 +20,8 @@ node.override['mediawiki']['tarball']['url'] = "https://releases.wikimedia.org/ node.override['mediawiki']['language_code'] = 'en' node.override['mediawiki']['server_name'] = 'wiki.kosmos.org' node.override['mediawiki']['site_name'] = 'Kosmos Wiki' -node.override['mediawiki']['server'] = "https://#{node['mediawiki']['server_name']}" - +protocol = node.chef_environment == "development" ? "http" : "https" +node.override['mediawiki']['server'] = "#{protocol}://#{node['mediawiki']['server_name']}" mysql_credentials = Chef::EncryptedDataBagItem.load('credentials', 'mysql') mediawiki_credentials = Chef::EncryptedDataBagItem.load('credentials', 'mediawiki') @@ -50,22 +50,33 @@ end include_recipe "mediawiki" include_recipe "kosmos-nginx" include_recipe "mediawiki::nginx" -include_recipe "kosmos-base::letsencrypt" -execute "letsencrypt cert for wiki.kosmos.org" do - command "./certbot-auto certonly --webroot --agree-tos --email ops@5apps.com --webroot-path #{node['mediawiki']['docroot_dir']} -d wiki.kosmos.org -n" - cwd "/usr/local/certbot" - not_if { File.exist? "/etc/letsencrypt/live/wiki.kosmos.org/fullchain.pem" } - notifies :reload, "service[nginx]", :delayed +unless node.chef_environment == "development" + include_recipe "kosmos-base::letsencrypt" + + execute "letsencrypt cert for wiki.kosmos.org" do + command "./certbot-auto certonly --webroot --agree-tos --email ops@5apps.com --webroot-path #{node['mediawiki']['docroot_dir']} -d wiki.kosmos.org -n" + cwd "/usr/local/certbot" + not_if { File.exist? "/etc/letsencrypt/live/wiki.kosmos.org/fullchain.pem" } + notifies :reload, "service[nginx]", :delayed + end + + execute "letsencrypt cert for wiki.kosmos.org" do + command "./certbot-auto certonly --webroot --agree-tos --email ops@5apps.com --webroot-path #{node["mediawiki"]["docroot_dir"]} -d wiki.kosmos.org -n" + cwd "/usr/local/certbot" + not_if { File.exist? "/etc/letsencrypt/live/wiki.kosmos.org/fullchain.pem" } + notifies :reload, "service[nginx]", :delayed + end end - +ssl_cert = "/etc/letsencrypt/live/wiki.kosmos.org/fullchain.pem" +ssl_key = "/etc/letsencrypt/live/wiki.kosmos.org/privkey.pem" template "#{node['nginx']['dir']}/sites-available/mediawiki" do source "nginx.conf.erb" variables( docroot: node['mediawiki']['webdir'], server_name: node['mediawiki']['server_name'], - ssl_cert: "/etc/letsencrypt/live/wiki.kosmos.org/fullchain.pem", - ssl_key: "/etc/letsencrypt/live/wiki.kosmos.org/privkey.pem" + ssl_cert: ssl_cert, + ssl_key: ssl_key ) action :create notifies :reload, "service[nginx]", :delayed @@ -90,7 +101,11 @@ end # MediawikiHubot extension # requires curl extension -package "php5-curl" +if platform?('ubuntu') && node[:platform_version].to_f < 16.04 + package "php5-curl" +else + package "php-curl" +end ark "MediawikiHubot" do url "https://github.com/67P/mediawiki-hubot/archive/master.zip" @@ -156,12 +171,14 @@ $wgArticlePath = "/$1"; end end -node.override["backup"]["mysql"]["host"] = "localhost" -node.override["backup"]["mysql"]["username"] = "root" -node.override["backup"]["mysql"]["password"] = node["mediawiki"]["db"]["root_password"] -unless node["backup"]["mysql"]["databases"].include? 'mediawikidb' - node.override["backup"]["mysql"]["databases"] = - node["backup"]["mysql"]["databases"].to_a << "mediawikidb" -end +unless node.chef_environment == "development" + node.override["backup"]["mysql"]["host"] = "localhost" + node.override["backup"]["mysql"]["username"] = "root" + node.override["backup"]["mysql"]["password"] = node["mediawiki"]["db"]["root_password"] + unless node["backup"]["mysql"]["databases"].include? 'mediawikidb' + node.override["backup"]["mysql"]["databases"] = + node["backup"]["mysql"]["databases"].to_a << "mediawikidb" + end -include_recipe "backup" + include_recipe "backup" +end diff --git a/site-cookbooks/kosmos-mediawiki/templates/default/nginx.conf.erb b/site-cookbooks/kosmos-mediawiki/templates/default/nginx.conf.erb index c5afe43..863a5c4 100644 --- a/site-cookbooks/kosmos-mediawiki/templates/default/nginx.conf.erb +++ b/site-cookbooks/kosmos-mediawiki/templates/default/nginx.conf.erb @@ -1,6 +1,8 @@ server { listen 80; - listen 443 ssl http2; + <% if File.exist?(@ssl_cert) && File.exist?(@ssl_key) -%> + listen 443 ssl; + <% end -%> server_name <%= @server_name %>; access_log /var/log/nginx/<%= @server_name %>.access.log; @@ -11,6 +13,7 @@ server { location / { try_files $uri $uri/ /index.php?$args; + <% if File.exist?(@ssl_cert) && File.exist?(@ssl_key) -%> set $redirect_to_ssl "no"; if ($ssl_protocol = "") { set $redirect_to_ssl "yes"; @@ -18,6 +21,7 @@ server { if ($redirect_to_ssl = yes) { rewrite ^(.*) https://$host$1 permanent; } + <% end -%> } location ~ \.php$ { @@ -30,7 +34,9 @@ server { fastcgi_param HTTP_PROXY ""; } + <% if File.exist?(@ssl_cert) && File.exist?(@ssl_key) -%> add_header Strict-Transport-Security "max-age=15768000; includeSubDomains"; ssl_certificate <%= @ssl_cert %>; ssl_certificate_key <%= @ssl_key %>; + <% end -%> } diff --git a/site-cookbooks/kosmos-wordpress/metadata.rb b/site-cookbooks/kosmos-wordpress/metadata.rb index 9b77fff..ea82bfd 100644 --- a/site-cookbooks/kosmos-wordpress/metadata.rb +++ b/site-cookbooks/kosmos-wordpress/metadata.rb @@ -8,3 +8,6 @@ version '0.1.0' depends 'wordpress' depends 'php-fpm' +depends 'backup' +depends 'kosmos-base' +depends 'kosmos-nginx' diff --git a/site-cookbooks/kosmos-wordpress/recipes/default.rb b/site-cookbooks/kosmos-wordpress/recipes/default.rb index c03b946..ca0aaea 100644 --- a/site-cookbooks/kosmos-wordpress/recipes/default.rb +++ b/site-cookbooks/kosmos-wordpress/recipes/default.rb @@ -12,7 +12,6 @@ mysql_credentials = Chef::EncryptedDataBagItem.load('credentials', 'mysql') node.override['wordpress']['db']['root_password'] = mysql_credentials["root_password"] node.override['wordpress']['server_name'] = "blog.kosmos.org" node.override['wordpress']['server_aliases'] = ["blog.kosmos.org"] -node.override['wordpress']['db']['mysql_version'] = "5.6" node.override['wordpress']['server_port'] = "443" credentials = Chef::EncryptedDataBagItem.load('credentials', 'wordpress') node.set['wordpress']['db']['pass'] = credentials["db_pass"] @@ -27,11 +26,13 @@ node.set['wordpress']['salt']['nonce'] = credentials["salt_nonce"] include_recipe 'kosmos-wordpress::nginx' -node.override["backup"]["mysql"]["host"] = "localhost" -node.override["backup"]["mysql"]["username"] = "root" -node.override["backup"]["mysql"]["password"] = node["mediawiki"]["db"]["root_password"] -unless node["backup"]["mysql"]["databases"].include? "wordpressdb" - node.override["backup"]["mysql"]["databases"] = - node["backup"]["mysql"]["databases"].to_a << "wordpressdb" +unless node.chef_environment == "development" + node.override["backup"]["mysql"]["host"] = "localhost" + node.override["backup"]["mysql"]["username"] = "root" + node.override["backup"]["mysql"]["password"] = node["wordpress"]["db"]["root_password"] + unless node["backup"]["mysql"]["databases"].include? "wordpressdb" + node.override["backup"]["mysql"]["databases"] = + node["backup"]["mysql"]["databases"].to_a << "wordpressdb" + end + include_recipe "backup" end -include_recipe "backup" diff --git a/site-cookbooks/kosmos-wordpress/recipes/nginx.rb b/site-cookbooks/kosmos-wordpress/recipes/nginx.rb index a2b1828..6d04427 100644 --- a/site-cookbooks/kosmos-wordpress/recipes/nginx.rb +++ b/site-cookbooks/kosmos-wordpress/recipes/nginx.rb @@ -9,35 +9,9 @@ node.set_unless['php-fpm']['pools'] = [] -include_recipe "php-fpm::configure" +include_recipe "php-fpm" include_recipe 'php-fpm::repository' unless node['php-fpm']['skip_repository_install'] -include_recipe "kosmos-base::letsencrypt" - -php_fpm_package_name = if node['php-fpm']['package_name'].nil? - if platform_family?("rhel") - "php-fpm" - else - "php5-fpm" - end - else - node['php-fpm']['package_name'] - end - -package php_fpm_package_name do - action :upgrade -end - -php_fpm_service_name = if node['php-fpm']['service_name'].nil? - php_fpm_package_name - else - node['php-fpm']['service_name'] - end - -service "php-fpm" do - service_name php_fpm_service_name - supports start: true, stop: true, restart: true, reload: true - action [:enable, :start] -end +include_recipe "php-fpm::install" php_fpm_pool "www" do enable false @@ -47,9 +21,6 @@ php_fpm_pool "wordpress" do listen "127.0.0.1:9001" user node['wordpress']['install']['user'] group node['wordpress']['install']['group'] - if node['platform'] == 'ubuntu' && node['platform_version'] == '10.04' - process_manager 'dynamic' - end listen_owner node['wordpress']['install']['user'] listen_group node['wordpress']['install']['group'] php_options node['wordpress']['php_options'] @@ -63,13 +34,19 @@ include_recipe "kosmos-nginx" include_recipe "wordpress::app" -execute "letsencrypt cert for blog.kosmos.org" do - command "./certbot-auto certonly --webroot --agree-tos --email ops@5apps.com --webroot-path #{node['wordpress']['dir']} -d blog.kosmos.org -n" - cwd "/usr/local/certbot" - not_if { File.exist? "/etc/letsencrypt/live/blog.kosmos.org/fullchain.pem" } - notifies :reload, "service[nginx]", :delayed +unless node.chef_environment == "development" + include_recipe "kosmos-base::letsencrypt" + + execute "letsencrypt cert for blog.kosmos.org" do + command "./certbot-auto certonly --webroot --agree-tos --email ops@5apps.com --webroot-path #{node['wordpress']['dir']} -d blog.kosmos.org -n" + cwd "/usr/local/certbot" + not_if { File.exist? "/etc/letsencrypt/live/blog.kosmos.org/fullchain.pem" } + notifies :reload, "service[nginx]", :delayed + end end +ssl_cert = "/etc/letsencrypt/live/blog.kosmos.org/fullchain.pem" +ssl_key = "/etc/letsencrypt/live/blog.kosmos.org/privkey.pem" template "#{node['nginx']['dir']}/sites-available/wordpress" do source "nginx.conf.erb" variables( @@ -77,8 +54,8 @@ template "#{node['nginx']['dir']}/sites-available/wordpress" do server_name: node['wordpress']['server_name'], server_aliases: node['wordpress']['server_aliases'], server_port: node['wordpress']['server_port'], - ssl_cert: "/etc/letsencrypt/live/blog.kosmos.org/fullchain.pem", - ssl_key: "/etc/letsencrypt/live/blog.kosmos.org/privkey.pem" + ssl_cert: ssl_cert, + ssl_key: ssl_key ) action :create notifies :reload, "service[nginx]", :delayed diff --git a/site-cookbooks/kosmos-wordpress/templates/default/nginx.conf.erb b/site-cookbooks/kosmos-wordpress/templates/default/nginx.conf.erb index 3477c1b..930e05a 100644 --- a/site-cookbooks/kosmos-wordpress/templates/default/nginx.conf.erb +++ b/site-cookbooks/kosmos-wordpress/templates/default/nginx.conf.erb @@ -15,6 +15,7 @@ server { location / { try_files $uri $uri/ /index.php?$args; + <% if File.exist?(@ssl_cert) && File.exist?(@ssl_key) -%> set $redirect_to_ssl "no"; if ($ssl_protocol = "") { set $redirect_to_ssl "yes"; @@ -22,6 +23,7 @@ server { if ($redirect_to_ssl = yes) { rewrite ^(.*) https://$host$1 permanent; } + <% end -%> } location ~ \.php$ { diff --git a/site-cookbooks/sockethub/recipes/proxy.rb b/site-cookbooks/sockethub/recipes/proxy.rb index 3961386..7d5a3ba 100644 --- a/site-cookbooks/sockethub/recipes/proxy.rb +++ b/site-cookbooks/sockethub/recipes/proxy.rb @@ -40,6 +40,8 @@ template "#{node['nginx']['dir']}/sites-available/sockethub" do end unless node.chef_environment == "development" + include_recipe "kosmos-base::letsencrypt" + execute "letsencrypt cert for sockethub.kosmos.org" do command "./certbot-auto certonly --webroot --agree-tos --email ops@5apps.com --webroot-path /var/www/sockethub -d sockethub.kosmos.org -n" cwd "/usr/local/certbot"