.
*
*/
// In place of enumerator support: The jobstatus enum-defineamajig
define('H01_BUILDSERVICE_JOBSTATUS_UNKNOWN',0);
define('H01_BUILDSERVICE_JOBSTATUS_RUNNING',1);
define('H01_BUILDSERVICE_JOBSTATUS_COMPLETED',2);
define('H01_BUILDSERVICE_JOBSTATUS_FAILED',3);
// In place of enumerator support: The fieldtype enum-defineamajig
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING','string');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_LONGTEXT','longtext');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_INTEGER','integer');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_FLOAT','float');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM','item');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_BOOLEAN','boolean');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_DATETIME','datetime');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL','url');
define('H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_IMAGE','image');
class H01_BUILDSERVICE {
public static $MAXSOURCEFILESIZE = 1024000; // 1MB
///TODO: The supported targets list should be automatically generated and is available trough the
///OBS web api. For now they're here, as this is faster to build for now. Yes, it's ugly :P
public static $BUILDSERVICES = array (
1=>array (
'id'=>'obs',
'name'=>'openSUSE Build Service',
'registrationurl'=>'https://secure-www.novell.com/selfreg/jsp/createOpenSuseAccount.jsp?target=https://build.opensuse.org/',
'apiurl'=>'http://api.opensuse.org/',
'statusurl'=>'https://build.opensuse.org/package/live_build_log?arch=ARCH&package=PACKAGE&project=PROJECT&repository=REPOSITORY',
'supportedtargets'=>array(
array('id'=>'1', 'name'=>'CentOS 5 32bit Intel', 'repository'=>'CentOS_CentOS-5', 'arch'=>'i586'),
array('id'=>'2', 'name'=>'CentOS 5 64bit Intel', 'repository'=>'CentOS_CentOS-5', 'arch'=>'x86_64'),
array('id'=>'3', 'name'=>'Debian 5.0 32bit Intel', 'repository'=>'Debian_5.0', 'arch'=>'i586'),
array('id'=>'4', 'name'=>'Debian 5.0 64bit Intel', 'repository'=>'Debian_5.0', 'arch'=>'x86_64'),
array('id'=>'5', 'name'=>'Debian Etch 32bit Intel', 'repository'=>'Debian_Etch', 'arch'=>'i586'),
array('id'=>'6', 'name'=>'Debian Etch 64bit Intel', 'repository'=>'Debian_Etch', 'arch'=>'x86_64'),
array('id'=>'7', 'name'=>'Fedora 12 32bit Intel', 'repository'=>'Fedora_12', 'arch'=>'i586'),
array('id'=>'8', 'name'=>'Fedora 12 64bit Intel', 'repository'=>'Fedora_12', 'arch'=>'x86_64'),
array('id'=>'9', 'name'=>'Fedora 13 32bit Intel', 'repository'=>'Fedora_13', 'arch'=>'i586'),
array('id'=>'10','name'=>'Fedora 13 64bit Intel', 'repository'=>'Fedora_13', 'arch'=>'x86_64'),
array('id'=>'11','name'=>'Mandriva 2009.1 32bit Intel', 'repository'=>'Mandriva_2009.1', 'arch'=>'i586'),
array('id'=>'12','name'=>'Mandriva 2009.1 64bit Intel', 'repository'=>'Mandriva_2009.1', 'arch'=>'x86_64'),
array('id'=>'13','name'=>'Mandriva 2010 32bit Intel', 'repository'=>'Mandriva_2010', 'arch'=>'i586'),
array('id'=>'14','name'=>'Mandriva 2010 64bit Intel', 'repository'=>'Mandriva_2010', 'arch'=>'x86_64'),
array('id'=>'15','name'=>'Mandriva 2010.1 32bit Intel', 'repository'=>'Mandriva_2010.1', 'arch'=>'i586'),
array('id'=>'16','name'=>'Mandriva 2010.1 64bit Intel', 'repository'=>'Mandriva_2010.1', 'arch'=>'x86_64'),
array('id'=>'17','name'=>'openSUSE 11.1 32bit Intel', 'repository'=>'openSUSE_11.1', 'arch'=>'i586'),
array('id'=>'18','name'=>'openSUSE 11.1 64bit Intel', 'repository'=>'openSUSE_11.1', 'arch'=>'x86_64'),
array('id'=>'19','name'=>'openSUSE 11.2 32bit Intel', 'repository'=>'openSUSE_11.2', 'arch'=>'i586'),
array('id'=>'20','name'=>'openSUSE 11.2 64bit Intel', 'repository'=>'openSUSE_11.2', 'arch'=>'x86_64'),
array('id'=>'21','name'=>'openSUSE 11.3 32bit Intel', 'repository'=>'openSUSE_11.3', 'arch'=>'i586'),
array('id'=>'22','name'=>'openSUSE 11.3 64bit Intel', 'repository'=>'openSUSE_11.3', 'arch'=>'x86_64'),
array('id'=>'23','name'=>'openSUSE Factory 32bit Intel', 'repository'=>'openSUSE_Factory','arch'=>'i586'),
array('id'=>'24','name'=>'openSUSE Factory 64bit Intel', 'repository'=>'openSUSE_Factory','arch'=>'x86_64'),
array('id'=>'25','name'=>'RedHat Enterprise Linux 4 32bit Intel', 'repository'=>'RedHat_RHEL-4', 'arch'=>'i586'),
array('id'=>'26','name'=>'RedHat Enterprise Linux 4 64bit Intel', 'repository'=>'RedHat_RHEL-4', 'arch'=>'x86_64'),
array('id'=>'27','name'=>'RedHat Enterprise Linux 5 32bit Intel', 'repository'=>'RedHat_RHEL-5', 'arch'=>'i586'),
array('id'=>'28','name'=>'RedHat Enterprise Linux 5 64bit Intel', 'repository'=>'RedHat_RHEL-5', 'arch'=>'x86_64'),
array('id'=>'29','name'=>'SUSE Linux Enterprise 9 32bit Intel', 'repository'=>'SLES_9', 'arch'=>'i586'),
array('id'=>'30','name'=>'SUSE Linux Enterprise 9 64bit Intel', 'repository'=>'SLES_9', 'arch'=>'x86_64'),
array('id'=>'31','name'=>'SUSE Linux Enterprise 10 SDK 32bit Intel','repository'=>'SLE_10_SDK', 'arch'=>'i586'),
array('id'=>'32','name'=>'SUSE Linux Enterprise 10 SDK 64bit Intel','repository'=>'SLE_10_SDK', 'arch'=>'x86_64'),
array('id'=>'33','name'=>'SUSE Linux Enterprise 11 32bit Intel', 'repository'=>'SLE_11', 'arch'=>'i586'),
array('id'=>'34','name'=>'SUSE Linux Enterprise 11 64bit Intel', 'repository'=>'SLE_11', 'arch'=>'x86_64'),
array('id'=>'35','name'=>'SUSE Linux Enterprise 11 SP1 32bit Intel','repository'=>'SLE_11_SP1', 'arch'=>'i586'),
array('id'=>'36','name'=>'SUSE Linux Enterprise 11 SP1 64bit Intel','repository'=>'SLE_11_SP1', 'arch'=>'x86_64'),
array('id'=>'37','name'=>'xUbuntu 10.04 32bit Intel', 'repository'=>'xUbuntu_10.04', 'arch'=>'i586'),
array('id'=>'38','name'=>'xUbuntu 10.04 64bit Intel', 'repository'=>'xUbuntu_10.04', 'arch'=>'x86_64'),
array('id'=>'39','name'=>'xUbuntu 6.06 32bit Intel', 'repository'=>'xUbuntu_6.06', 'arch'=>'i586'),
array('id'=>'40','name'=>'xUbuntu 6.06 64bit Intel', 'repository'=>'xUbuntu_6.06', 'arch'=>'x86_64'),
array('id'=>'41','name'=>'xUbuntu 8.04 32bit Intel', 'repository'=>'xUbuntu_8.04', 'arch'=>'i586'),
array('id'=>'42','name'=>'xUbuntu 8.04 64bit Intel', 'repository'=>'xUbuntu_8.04', 'arch'=>'x86_64'),
array('id'=>'43','name'=>'xUbuntu 9.04 32bit Intel', 'repository'=>'xUbuntu_9.04', 'arch'=>'i586'),
array('id'=>'44','name'=>'xUbuntu 9.04 64bit Intel', 'repository'=>'xUbuntu_9.04', 'arch'=>'x86_64'),
array('id'=>'45','name'=>'xUbuntu 9.10 32bit Intel', 'repository'=>'xUbuntu_9.10', 'arch'=>'i586'),
array('id'=>'46','name'=>'xUbuntu 9.10 64bit Intel', 'repository'=>'xUbuntu_9.10', 'arch'=>'x86_64')
),
'projectTemplate'=>'
OCS Buildservice Project
This project was automatically created by the Open Collaboration Services Build Service module.
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
i586
x86_64
'
),
// This build service is disabled for the following reason:
// No public signup. Usability gestalt law: Do not present the user with options they have no way
// of enabling.
// 2=>array (
// 'id'=>'mbs',
// 'name'=>'MeeGo Build Service',
// 'registrationurl'=>'http://build.meego.com/',
// 'apiurl'=>'http://api.meego.org/',
// 'statusurl'=>'https://build.meego.org/package/live_build_log?arch=ARCH&package=PACKAGE&project=PROJECT&repository=REPOSITORY',
// 'supportedtargets'=>array(
// array('id'=>'1','name'=>'MeeGo 1.0 Intel','repository'=>'','arch'=>''),
// array('id'=>'2','name'=>'MeeGo 1.0 ARM','repository'=>'','arch'=>''),
// array('id'=>'3','name'=>'MeeGo 1.1 Intel','repository'=>'','arch'=>''),
// array('id'=>'4','name'=>'MeeGo 1.1 ARM','repository'=>'','arch'=>'')
// ),
// 'projectTemplate'=>''
// ),
3=>array (
'id'=>'pmbs',
'name'=>'MeeGo Community Build Service',
'registrationurl'=>'http://build.pub.meego.com/',
'apiurl'=>'http://api.pub.meego.org/',
'statusurl'=>'https://build.pub.meego.org/package/live_build_log?arch=ARCH&package=PACKAGE&project=PROJECT&repository=REPOSITORY',
'supportedtargets'=>array(
array('id'=>'1', 'name'=>'MeeGo 1.1 Core 32bit Intel', 'repository'=>'meego_1.1_core', 'arch'=>'i586'),
array('id'=>'2', 'name'=>'MeeGo 1.1 Core ARM v7el', 'repository'=>'meego_1.1_core', 'arch'=>'armv7el'),
array('id'=>'3', 'name'=>'MeeGo 1.1 Core Handset 32bit Intel', 'repository'=>'meego_1.1_core_handser', 'arch'=>'i586'),
array('id'=>'4', 'name'=>'MeeGo 1.1 Core Handset v7el', 'repository'=>'meego_1.1_core_handset', 'arch'=>'armv7el'),
array('id'=>'5', 'name'=>'MeeGo 1.1 Core IVI 32bit Intel', 'repository'=>'meego_1.1_core_IVI', 'arch'=>'i586'),
array('id'=>'6', 'name'=>'MeeGo 1.1 Core IVI ARM v7el', 'repository'=>'meego_1.1_core_IVI', 'arch'=>'armv7el'),
array('id'=>'7', 'name'=>'MeeGo 1.1 Core Netbook 32bit Intel', 'repository'=>'meego_1.1_core_Netbook', 'arch'=>'i586'),
array('id'=>'8', 'name'=>'MeeGo 1.1 Core Netbook ARM v7el', 'repository'=>'meego_1.1_core_Netbook', 'arch'=>'armv7el'),
array('id'=>'9', 'name'=>'MeeGo 1.1 Extras 32bit Intel', 'repository'=>'meego_1.1_extras', 'arch'=>'i586'),
array('id'=>'10','name'=>'MeeGo 1.1 Extras ARM v7el', 'repository'=>'meego_1.1_extras', 'arch'=>'armv7el'),
array('id'=>'11','name'=>'MeeGo 1.1 Extras IVI 32bit Intel', 'repository'=>'meego_1.1_extras_IVI', 'arch'=>'i586'),
array('id'=>'12','name'=>'MeeGo 1.1 Extras IVI ARM v7el', 'repository'=>'meego_1.1_extras_IVI', 'arch'=>'armv7el'),
array('id'=>'13','name'=>'MeeGo 1.1 Extras Handset 32bit Intel', 'repository'=>'meego_1.1_extras_handset', 'arch'=>'i586'),
array('id'=>'14','name'=>'MeeGo 1.1 Extras Handset ARM v7el', 'repository'=>'meego_1.1_extras_handset', 'arch'=>'armv7el'),
array('id'=>'15','name'=>'MeeGo 1.1 Extras Netbook 32bit Intel', 'repository'=>'meego_1.1_extras_Netbook', 'arch'=>'i586'),
array('id'=>'16','name'=>'MeeGo 1.1 Extras Netbook ARM v7el', 'repository'=>'meego_1.1_extras_Netbook', 'arch'=>'armv7el'),
array('id'=>'17','name'=>'MeeGo Current Extras 32bit Intel', 'repository'=>'meego_current_extras', 'arch'=>'i586'),
array('id'=>'18','name'=>'MeeGo Current Extras ARM v7el', 'repository'=>'meego_current_extras', 'arch'=>'armv7el'),
array('id'=>'19','name'=>'MeeGo Current Extras IVI 32bit Intel', 'repository'=>'meego_current_extras_IVI', 'arch'=>'i586'),
array('id'=>'20','name'=>'MeeGo Current Extras IVI ARM v7el', 'repository'=>'meego_current_extras_IVI', 'arch'=>'armv7el'),
array('id'=>'21','name'=>'MeeGo Current Extras Handset 32bit Intel', 'repository'=>'meego_current_extras_handset','arch'=>'i586'),
array('id'=>'22','name'=>'MeeGo Current Extras Handset ARM v7el', 'repository'=>'meego_current_extras_handset','arch'=>'armv7el'),
array('id'=>'23','name'=>'MeeGo Current Extras Netbook 32bit Intel', 'repository'=>'meego_current_extras_Netbook','arch'=>'i586'),
array('id'=>'24','name'=>'MeeGo Current Extras Netbook ARM v7el', 'repository'=>'meego_current_extras_Netbook','arch'=>'armv7el')
),
'projectTemplate'=>'
OCS Buildservice Project
This project was automatically created by the Open Collaboration Services Build Service module.
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
i586
armv7el
'
)
);
public static $PUBLISHERS = array (
0=>array(
'id'=>0,
'name'=>'openDesktop.org',
'registrationurl'=>'',
//'apiurl'=>'http://api.opendesktop.dev.hive01.com/v1/',
'apiurl'=>'http://api.opendesktop.org/v1/',
'fields'=>array(
array(
'name'=>'Type',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/categories',
'fieldsize'=>0,
'required'=>true
),
array(
'name'=>'Name',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING,
'options'=>array(),
'fieldsize'=>256,
'required'=>true
),
array(
'name'=>'Summary',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Version',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING,
'options'=>array(),
'fieldsize'=>256,
'required'=>true
),
array(
'name'=>'License',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING,
'options'=>'content/licenses',
'fieldsize'=>256,
'required'=>true
),
array(
'name'=>'License Text',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_LONGTEXT,
'options'=>array(),
'fieldsize'=>36767,
'required'=>false
),
array(
'name'=>'Description',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_LONGTEXT,
'options'=>array(),
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Base Dependency',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/dependencies',
'fieldsize'=>0,
'required'=>false
),
array(
'name'=>'Feedbackurl',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 2',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 2',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 3',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 3',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 4',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 4',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 5',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 5',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 6',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 6',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 7',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 7',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 8',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 8',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 9',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 9',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Homepage 10',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Homepage Type 10',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>'content/homepages',
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Video 1',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Video 2',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Video 3',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_URL,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Change Log',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_LONGTEXT,
'options'=>array(),
'fieldsize'=>32767,
'required'=>false
),
array(
'name'=>'Enable Donation',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,
'options'=>array(
'yes'=>'Yes',
'no'=>'No' // This breaks the OCS standard!! The response should be '' but the xml serialiser craps itself on that.
),
'fieldsize'=>2048,
'required'=>false
),
array(
'name'=>'Donation Reason',
'fieldtype'=>H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING,
'options'=>array(),
'fieldsize'=>2048,
'required'=>false
)
),
'targets'=>array(
'CentOS 5 32bit Intel'=>array('repository'=>'CentOS_CentOS-5','arch'=>'i586','distribution'=>'20000'),
'CentOS 5 64bit Intel'=>array('repository'=>'CentOS_CentOS-5','arch'=>'x86_64','distribution'=>'20000'),
'Debian 5.0 32bit Intel'=>array('repository'=>'Debian_5.0','arch'=>'i586','distribution'=>'1100'),
'Debian 5.0 64bit Intel'=>array('repository'=>'Debian_5.0','arch'=>'x86_64','distribution'=>'1100'),
'Debian Etch 32bit Intel'=>array('repository'=>'Debian_Etch','arch'=>'i586','distribution'=>'1100'),
'Debian Etch 64bit Intel'=>array('repository'=>'Debian_Etch','arch'=>'x86_64','distribution'=>'1100'),
'Fedora 12 32bit Intel'=>array('repository'=>'Fedora_12','arch'=>'i586','distribution'=>'800'),
'Fedora 12 64bit Intel'=>array('repository'=>'Fedora_12','arch'=>'x86_64','distribution'=>'800'),
'Fedora 13 32bit Intel'=>array('repository'=>'Fedora_13','arch'=>'i586','distribution'=>'800'),
'Fedora 13 64bit Intel'=>array('repository'=>'Fedora_13','arch'=>'x86_64','distribution'=>'800'),
'Mandriva 2009.1 32bit Intel'=>array('repository'=>'Mandriva_2009.1','arch'=>'i586','distribution'=>'1300'),
'Mandriva 2009.1 64bit Intel'=>array('repository'=>'Mandriva_2009.1','arch'=>'x86_64','distribution'=>'1300'),
'Mandriva 2010 32bit Intel'=>array('repository'=>'Mandriva_2010','arch'=>'i586','distribution'=>'1300'),
'Mandriva 2010 64bit Intel'=>array('repository'=>'Mandriva_2010','arch'=>'x86_64','distribution'=>'1300'),
'Mandriva 2010.1 32bit Intel'=>array('repository'=>'Mandriva_2010.1','arch'=>'i586','distribution'=>'1300'),
'Mandriva 2010.1 64bit Intel'=>array('repository'=>'Mandriva_2010.1','arch'=>'x86_64','distribution'=>'1300'),
'openSUSE 11.1 32bit Intel'=>array('repository'=>'openSUSE_11.1','arch'=>'i586','distribution'=>'600'),
'openSUSE 11.1 64bit Intel'=>array('repository'=>'openSUSE_11.1','arch'=>'x86_64','distribution'=>'600'),
'openSUSE 11.2 32bit Intel'=>array('repository'=>'openSUSE_11.2','arch'=>'i586','distribution'=>'600'),
'openSUSE 11.2 64bit Intel'=>array('repository'=>'openSUSE_11.2','arch'=>'x86_64','distribution'=>'600'),
'openSUSE 11.3 32bit Intel'=>array('repository'=>'openSUSE_11.3','arch'=>'i586','distribution'=>'600'),
'openSUSE 11.3 64bit Intel'=>array('repository'=>'openSUSE_11.3','arch'=>'x86_64','distribution'=>'600'),
'openSUSE Factory 32bit Intel'=>array('repository'=>'openSUSE_Factory','arch'=>'i586','distribution'=>'600'),
'openSUSE Factory 64bit Intel'=>array('repository'=>'openSUSE_Factory','arch'=>'x86_64','distribution'=>'600'),
'RedHat Enterprise Linux 4 32bit Intel'=>array('repository'=>'RedHat_RHEL-4','arch'=>'i586','distribution'=>'900'),
'RedHat Enterprise Linux 4 64bit Intel'=>array('repository'=>'RedHat_RHEL-4','arch'=>'x86_64','distribution'=>'900'),
'RedHat Enterprise Linux 5 32bit Intel'=>array('repository'=>'RedHat_RHEL-5','arch'=>'i586','distribution'=>'900'),
'RedHat Enterprise Linux 5 64bit Intel'=>array('repository'=>'RedHat_RHEL-5','arch'=>'x86_64','distribution'=>'900'),
'SUSE Linux Enterprise 9 32bit Intel'=>array('repository'=>'SLES_9','arch'=>'i586','distribution'=>'600'),
'SUSE Linux Enterprise 9 64bit Intel'=>array('repository'=>'SLES_9','arch'=>'x86_64','distribution'=>'600'),
'SUSE Linux Enterprise 10 SDK 32bit Intel'=>array('repository'=>'SLE_10_SDK','arch'=>'i586','distribution'=>'600'),
'SUSE Linux Enterprise 10 SDK 64bit Intel'=>array('repository'=>'SLE_10_SDK','arch'=>'x86_64','distribution'=>'600'),
'SUSE Linux Enterprise 11 32bit Intel'=>array('repository'=>'SLE_11','arch'=>'i586','distribution'=>'600'),
'SUSE Linux Enterprise 11 64bit Intel'=>array('repository'=>'SLE_11','arch'=>'x86_64','distribution'=>'600'),
'SUSE Linux Enterprise 11 SP1 32bit Intel'=>array('repository'=>'SLE_11_SP1','arch'=>'i586','distribution'=>'600'),
'SUSE Linux Enterprise 11 SP1 64bit Intel'=>array('repository'=>'SLE_11_SP1','arch'=>'x86_64','distribution'=>'600'),
'xUbuntu 10.04 32bit Intel'=>array('repository'=>'xUbuntu_10.04','arch'=>'i586','distribution'=>'1200'),
'xUbuntu 10.04 64bit Intel'=>array('repository'=>'xUbuntu_10.04','arch'=>'x86_64','distribution'=>'1200'),
'xUbuntu 6.06 32bit Intel'=>array('repository'=>'xUbuntu_6.06','arch'=>'i586','distribution'=>'1200'),
'xUbuntu 6.06 64bit Intel'=>array('repository'=>'xUbuntu_6.06','arch'=>'x86_64','distribution'=>'1200'),
'xUbuntu 8.04 32bit Intel'=>array('repository'=>'xUbuntu_8.04','arch'=>'i586','distribution'=>'1200'),
'xUbuntu 8.04 64bit Intel'=>array('repository'=>'xUbuntu_8.04','arch'=>'x86_64','distribution'=>'1200'),
'xUbuntu 9.04 32bit Intel'=>array('repository'=>'xUbuntu_9.04','arch'=>'i586','distribution'=>'1200'),
'xUbuntu 9.04 64bit Intel'=>array('repository'=>'xUbuntu_9.04','arch'=>'x86_64','distribution'=>'1200'),
'xUbuntu 9.10 32bit Intel'=>array('repository'=>'xUbuntu_9.10','arch'=>'i586','distribution'=>'1200'),
'xUbuntu 9.10 64bit Intel'=>array('repository'=>'xUbuntu_9.10','arch'=>'x86_64','distribution'=>'1200')
)
)
);
/**
* Construct an sql update statement for use with H01_DB::update()
* @param string $tablename The name of the table to work on
* @param array $fields Key/value pairs of data fields and new values. Note that the values
* should be in the format required by SQL for the according field type
* @param string $clauses An optional string with extra clauses (e.g. "where id=9")
* @return string The sql query string appropriate for passing to H01_DB::update()
*/
static function buildupdatestatement($tablename, $fields=array(), $clauses=''){
$sqlquery=$tablename . ' set';
$separator='';
foreach($fields as $key=>$value){
$sqlquery.=$separator . ' ' . $key . '=' . $value;
$separator=',';
}
if($clauses!='')
$sqlquery.=' ' . $clauses;
return($sqlquery);
}
/// All these functions will as a start implement exactly the results provided in the specification
/// This is a total cheat, but allows us to rapidly get some test data ready ;)
// Project section
/**
* Create a new project in the build service
* @param string $user
* @param int $userdb
* @param string $name
* @param string $version
* @param string $license
* @param string $url
* @param array $developers
* @param string $summary
* @param string $description
* @param string $requirements
* @param string $specfile
* @return mixed Upon success, an array with the form projectid=>value will be returned, or NULL in the case the creation failed
*/
static function projectcreate($user,$userdb,$name,$version='',$license='',$url='',$developers='',$summary='',$description='',$requirements='',$specfile=''){
$newProjectID=NULL;
$sqlquery='into buildservice_projects (user,userdb,name,version,license,url,publishingfields,developers,summary,description,requirements,specfile,changed) values(';
// Get the current user's ID
$sqlquery.="\"$user\",$userdb,";
$sqlquery.='"' . addslashes($name) . '",';
$sqlquery.='"' . addslashes($version) . '",';
$sqlquery.='"' . addslashes($license) . '",';
$sqlquery.='"' . addslashes($url) . '",';
$sqlquery.='"' . serialize(array()) . '",';
$sqlquery.='"' . addslashes($developers) . '",';
$sqlquery.='"' . addslashes($summary) . '",';
$sqlquery.='"' . addslashes($description) . '",';
$sqlquery.='"' . addslashes($requirements) . '",';
$sqlquery.='"' . addslashes($specfile) . '",';
$sqlquery.='"'.time().'")';
$result = H01_DB::insert('buildservice_projects',$sqlquery);
if($result){
$newProjectID=H01_DB::insertid();
H01_DB::free_result($result);
}
// Store the project on all build services where we have an account
$obshandlers=H01_BUILDSERVICE::getbuildservicesforuser($user,$userdb);
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$newProjectID);
foreach($obshandlers as $obshandler) {
$projectStored=$obshandler->storeproject($projectData);
if(!$projectStored) {
// This should be passed back someow... Inside the array, and used the other side...
//echo $obshandler->errormessage();
}
}
return(array("projectid"=>$newProjectID));
}
/**
* Get the data for a project in the build service
* @param string $user
* @param int $userdb
* @param int $projectID
* @return mixed An empty array if no project was found, or an one-dimensional array containing key/value pairs of project data
*/
static function projectget($user,$userdb,$projectID){
$projectData=array();
$result=H01_DB::select('buildservice_projects','user,userdb,name,version,license,url,developers,summary,description,requirements,specfile,changed from buildservice_projects where id="'.addslashes($projectID).'"');
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
if($data["user"]==$user and $data["userdb"]==$userdb){
$projectData["projectid"]=$projectID;
$projectData["name"]=$data["name"];
$projectData["version"]=$data["version"];
$projectData["license"]=$data["license"];
$projectData["url"]=$data["url"];
$projectData["developers"]=$data["developers"];
$projectData["summary"]=$data["summary"];
$projectData["description"]=$data["description"];
$projectData["requirements"]=$data["requirements"];
$projectData["specfile"]=stripslashes($data["specfile"]);
}
}
H01_DB::free_result($result);
return(array("project"=>$projectData));
}
/**
* Delete a project in the build service
* @param string $user
* @param int $userdb
* @param int $projectID
* @return bool True if the project was successfully deleted, false otherwise
*/
static function projectdelete($user,$userdb,$projectID){
// Yes, this is double-fetching, so...
///TODO This function needs a bit of rewriting, to ensure we only grab the data once
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$projectID);
$returnVal=false;
$result=H01_DB::select('buildservice_projects','id from buildservice_projects where id='.addslashes($projectID).' and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
H01_DB::free_result($result);
$result=H01_DB::delete('buildservice_projects','from buildservice_projects where id='.addslashes($projectID));
$returnVal=true;
}
H01_DB::free_result($result);
if($returnVal) {
// Delete the project and all related data from the registered build services
$obshandlers=H01_BUILDSERVICE::getbuildservicesforuser($user,$userdb);
foreach($obshandlers as $obshandler) {
$obshandler->deleteproject($projectData);
}
// Remove all related files from our own server
$projectdir=CONFIG_DOCUMENT_ROOT.'/CONTENT/buildservice-files/'.$projectID;
//- delete all contents from the project directory
H01_BUILDSERVICE::rmdir_p($projectdir);
// delete project directory itself
@rmdir($projectdir);
}
return($returnVal);
}
/**
* Remove a directory recursively
* This function is copied from H01_CACHEADMIN::rmdir_p
* @param directory to remove $dir
* @return true/false
*/
static function rmdir_p($dir) {
$handle = opendir($dir);
while (false!==($FolderOrFile = readdir($handle))) {
if($FolderOrFile != '.' && $FolderOrFile != '..') {
if(is_dir($dir.'/'.$FolderOrFile)) {
H01_BUILDSERVICE::rmdir_p("$dir/$FolderOrFile");
} else {
@unlink($dir.'/'.$FolderOrFile);
}
}
}
closedir($handle);
return(true);
}
/**
* Edit the contents of an existing project
* @param string $user
* @param int $userdb
* @param int $projectID
* @param string $name
* @param string $version
* @param string $license
* @param string $url
* @param array $developers
* @param string $summary
* @param string $description
* @param string $requirements
* @param string $specfile
* @return bool True if the project was successfully deleted, false otherwise
*/
static function projectedit($user,$userdb,$projectID,$name=NULL,$version=NULL,$license=NULL,$url=NULL,$developers=NULL,$summary=NULL,$description=NULL,$requirements=NULL,$specfile=0){
$returnval=false;
$result=H01_DB::select("buildservice_projects","id from buildservice_projects where id=$projectID and user=\"$user\" and userdb=$userdb");
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
$fields=array();
if($name!=NULL)
$fields["name"]="\"" . addslashes($name) . "\"";
if($version!=NULL)
$fields["version"]="\"" . addslashes($version) . "\"";
if($license!=NULL)
$fields["license"]="\"" . addslashes($license) . "\"";
if($url!=NULL)
$fields["url"]="\"" . addslashes($url) . "\"";
if($developers!=NULL)
$fields["developers"]="\"" . addslashes($developers) . "\"";
if($summary!=NULL)
$fields["summary"]="\"" . addslashes($summary) . "\"";
if($description!=NULL)
$fields["description"]="\"" . addslashes($description) . "\"";
if($requirements!=NULL)
$fields["requirements"]="\"" . addslashes($requirements) . "\"";
$generateSpecfile=false;
if($specfile!==0) {
if($specfile=='') {
$generateSpecfile=true;
} else {
$fields["specfile"]="\"" . addslashes($specfile) . "\"";
}
}
$fields["changed"]=time();
$query=H01_BUILDSERVICE::buildupdatestatement('buildservice_projects', $fields,'where id='.addslashes($projectID));
if($query){
$result=H01_DB::update("buildservice_projects",$query);
H01_DB::free_result($result);
}
$returnval=true;
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$projectID);
if($generateSpecfile){
// We have to run this update here, otherwise the specfile changes will be staggered, and we
// can't have that, now can we? Right. We specifically ask for the openSuse OBS instance here
// and the reason for that is simple: obs-generator in its current shape sort of requires it,
// More exactly, it does not require the server, but certain parts of the code require the
// openSuse OBS setup to be there.
$suseOBS=H01_BUILDSERVICE::getbuildserviceforuser($user,$userdb,'obs');
if(isset($suseOBS)) {
$suseOBS->createfakecheckout($projectData,CONFIG_DOCUMENT_ROOT.'/CONTENT/buildservice-files/'.$projectID.'/');
unset($suseOBS);
}
$fields=array();
$fields["specfile"]="\"" . addslashes(H01_BUILDSERVICE::generatenewspecfile($projectData)) . "\"";
$query=H01_BUILDSERVICE::buildupdatestatement('buildservice_projects', $fields,'where id='.addslashes($projectID));
if($query){
$result=H01_DB::update("buildservice_projects",$query);
H01_DB::free_result($result);
}
}
// We don't need to refetch the project data - even though it is potentially outdated (due
// to the new specfile) this function never accesses the specfile, and as such that is not
// important.
// Store the project data onto all build services where the user has an account
$obshandlers=H01_BUILDSERVICE::getbuildservicesforuser($user,$userdb);
foreach($obshandlers as $obshandler) {
$projectStored=$obshandler->storeproject($projectData);
if(!$projectStored) {
///TODO This should be passed back someow, but we don't have an error reporter like that... Maybe we should build one ;)
//echo $obshandler->errormessage();
}
}
}
return($returnval);
}
/**
* List all the projects in the build service owned by the authorized user
* @param string $user
* @param int $userdb
* @return array A two-dimensional array of project data. This array can be empty, signifying the user has no projects
*/
static function projectlist($user,$userdb){
$projectList=array();
$result=H01_DB::select('buildservice_projects','id,name,version,license,url,developers,summary,description,requirements,specfile,changed from buildservice_projects where user="'.addslashes($user).'" and userdb='.CONFIG_USERDB);
$count=H01_DB::numrows($result);
for($i=0;$i$projectList));
}
/**
* Upload a new source bundle (a compressed file in .zip, .tar.gz or .tar.bz2 format) containing
* the source code of the project
* @param string $user
* @param int $userdb
* @param int $projectID
* @return bool Whether or not the upload was successful
*/
static function projectuploadsource($user,$userdb,$projectID){
$sucess=false;
$result=H01_DB::select('buildservice_projects','user,userdb,name,version,license,url,developers,summary,description,requirements,specfile,changed from buildservice_projects where id="'.addslashes($projectID).'"');
$data=H01_DB::fetch_assoc($result);
H01_DB::free_result($result);
if(count($data)>0){
if($data['user']==$user and $data['userdb']==$userdb){
// Yay, user is the right one and all that jazz!
if(isset($_FILES['source'])){
$check=H01_BUILDSERVICE::checkfileupload($_FILES['source']['name'],$_FILES['source']['size'],filesize($_FILES['source']['tmp_name']),H01_BUILDSERVICE::$MAXSOURCEFILESIZE);
if($check=='') {
$projectdir=CONFIG_DOCUMENT_ROOT.'/CONTENT/buildservice-files/'.$projectID.'/';
if(!file_exists($projectdir)) {
// Create the project dir
@mkdir($projectdir);
}
$newfile=$projectdir.$_FILES['source']['name'];
move_uploaded_file($_FILES['source']['tmp_name'],$newfile);
///FIXME Do we actually need to do this? The point being that OBS can, in fact, handle
///just about every comptessed package format under the sun...
// add here calls for conversion to the right package format
// Upload the new source file to all the build services the user is registered for
$obshandlers=H01_BUILDSERVICE::getbuildservicesforuser($user,$userdb);
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$projectID);
foreach($obshandlers as $obshandler) {
$obshandler->uploadsourcefile($projectData,$newfile,$_FILES['source']['name']);
// We don't handle the errors here, because we may or may not have a package for the
// project on any particular build service...
}
$error='';
}else{
$error=$check;
}
}else{
$error='please specify a source file for uploading';
}
}else{
$error='no access to project';
}
}else{
$error='project not found';
}
return($error);
}
// Remote Accounts section
/**
* List all accounts for the specified user
* @param string $user
* @param int $userdb
* @return Array of remoteaccount data
*/
static function remoteaccountslist($user,$userdb) {
$raList=array();
$result=H01_DB::select('buildservice_remoteaccounts','id,type,typeid,data,login,password from buildservice_remoteaccounts where user="'.addslashes($user).'" and userdb='.CONFIG_USERDB);
$count=H01_DB::numrows($result);
for($i=0;$i$raList));
}
/**
* Add a remote account entry for the specified user
* @param string $user
* @param int $userdb
* @param int $type The type of account (1 == build service, 2 == publisher)
* @param string $typeid The ID of the service the account pertains to
* @param string $data The data to enter into the data section (any arbitrary string data)
* @param string $login The user's login on the remote service
* @param string $password The user's password on the remote service
* @return The ID of the new entry if successful, or array with the keys 'code' and 'message' on error
*/
static function remoteaccountsadd($user,$userdb,$type,$typeid,$data,$login,$password) {
$newRaID=NULL;
$failure=false;
if($type==1 or $type==2) {
$found=false;
switch($type){
case 1:
$buildservice=0;
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key=>$value) {
if($typeid==$value['id']) {
$buildservice=$key;
break;
}
}
if($buildservice>0){
$found=true;
}
break;
case 2:
default:
$found=array_key_exists($typeid,H01_BUILDSERVICE::$PUBLISHERS);
break;
}
if($found) {
$sqlquery='into buildservice_remoteaccounts (user,userdb,type,typeid,data,login,password) values(';
// Get the current user's ID
$sqlquery.="\"$user\",$userdb,";
$sqlquery.='' . addslashes($type) . ',';
$sqlquery.='"' . addslashes($typeid) . '",';
$sqlquery.='"' . addslashes($data) . '",';
$sqlquery.='"' . addslashes($login) . '",';
$sqlquery.='"' . addslashes($password) . '")';
$result = H01_DB::insert('buildservice_remoteaccounts',$sqlquery);
if($result){
$newRaID=H01_DB::insertid();
H01_DB::free_result($result);
}
} else {
$failure=array('code'=>102,'message'=>'service id was not recognised');
}
} else {
$failure=array('code'=>101,'message'=>'no such service');
}
if($failure){
return($failure);
}
return(array("remoteaccountid"=>$newRaID));
}
/**
* Edit the specified remote account entry
* @param string $user
* @param int $userdb
* @param int $id The entry's ID
* @param string $login The user's login on the remote service
* @param string $password The user's password on the remote service
* @param string $data The data to enter into the data section (any arbitrary string data)
* @return True on success, false on failure
*/
static function remoteaccountsedit($user,$userdb,$id,$login,$password,$data) {
$returnval=false;
$result=H01_DB::select("buildservice_remoteaccounts",'id from buildservice_remoteaccounts where id=' . addslashes($id) . ' and user="' . addslashes($user) . '" and userdb=' . addslashes($userdb));
$tmpdata=H01_DB::fetch_assoc($result);
if(count($tmpdata)>0){
$fields=array();
if($login!=NULL)
$fields["login"]="\"" . addslashes($login) . "\"";
if($password!=NULL)
$fields["password"]="\"" . addslashes($password) . "\"";
if($data!=NULL)
$fields["data"]="\"" . addslashes($data) . "\"";
$query=H01_BUILDSERVICE::buildupdatestatement('buildservice_remoteaccounts', $fields,'where id='.addslashes($id));
if($query){
$result=H01_DB::update("buildservice_remoteaccounts",$query);
H01_DB::free_result($result);
}
$returnval=true;
}
return($returnval);
}
/**
* Fetch all known information about a specified remote account
* @param string $user
* @param int $userdb
* @param int $id
* @return An array containing the information, or array with the keys 'code' and 'message' on error
*/
static function remoteaccountsget($user,$userdb,$id) {
$raData=array();
$failure=false;
$result=H01_DB::select('buildservice_remoteaccounts','id,type,typeid,data,login,password from buildservice_remoteaccounts where id=' . addslashes($id) . ' and user="'.addslashes($user).'" and userdb='.CONFIG_USERDB);
$data=H01_DB::fetch_assoc($result);
if(count($data)>0) {
$raData['id']=$data['id'];
$raData['type']=$data['type'];
$raData['typeid']=$data['typeid'];
$raData['data']=$data['data'];
$raData['login']=$data['login'];
$raData['password']=$data['password'];
} else {
$failure=array('code'=>101,'message'=>'no such remote account');
}
H01_DB::free_result($result);
if($failure){
return($failure);
}
return(array("remoteaccount"=>$raData));
}
/**
* Delete the specified remote account entry
* @param string $user
* @param int $userdb
* @param int $id
* @return True if successful, false on error
*/
static function remoteaccountsremove($user,$userdb,$id) {
$returnVal=false;
$failure=false;
$result=H01_DB::select('buildservice_remoteaccounts','id from buildservice_remoteaccounts where id='.addslashes($id).' and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
H01_DB::free_result($result);
$result=H01_DB::delete('buildservice_remoteaccounts','from buildservice_remoteaccounts where id='.addslashes($id));
$returnVal=true;
} else {
$failure=array('code'=>101,'message'=>'no such remote account');
}
H01_DB::free_result($result);
if($failure){
return($failure);
}
return($returnVal);
}
/**
* Return an array with an instance of the buildservice abstractor for all the remote accounts
* for the specified user
* @param string $user
* @param int $userdb
* @return array An array containing an instance of the H01_BUILDSERVICE_OBS class for each remote build service account for the specified user
*/
static function getbuildservicesforuser($user,$userdb) {
$instances=array();
$accts=H01_BUILDSERVICE::remoteaccountslist($user,$userdb);
foreach($accts['remoteaccountslist'] as $account) {
// Only do this for build services, obviously...
if($account['type']==1) {
$bs=NULL;
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key => $tempbs) {
if($tempbs['id']==$account['typeid']) {
$bs=& H01_BUILDSERVICE::$BUILDSERVICES[$key];
break;
}
}
$instances[]=new H01_BUILDSERVICE_OBS($account['login'],$account['password'],$bs);
}
}
return($instances);
}
/**
* Return an instance of the buildservice abstractor for the specified user's account there
* @param string $user
* @param int $userdb
* @param string $buildserviceID
* @return H01_BUILDSERVICE_OBS An instance of the abstractor as appropriate to this user and build service combination
*/
static function getbuildserviceforuser($user,$userdb,$buildserviceID) {
$acctresult=H01_DB::select('buildservice_remoteaccounts','login,password from buildservice_remoteaccounts where type=1 and typeid="'.$buildserviceID.'" and user="'.$user.'" and userdb='.$userdb);
$acctdata=H01_DB::fetch_assoc($acctresult);
H01_DB::free_result($acctresult);
if(count($acctdata)==0) {
return(NULL);
}
$username=$acctdata['login'];
$password=$acctdata['password'];
$bs=NULL;
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key => $tempbs) {
if($tempbs['id']==$buildserviceID) {
$bs=& H01_BUILDSERVICE::$BUILDSERVICES[$key];
break;
}
}
// If this happens, then we have requested a build service for which the user has no account.
// We can only return NULL, and not a broken instance here...
if($bs===NULL) {
return(NULL);
}
return(new H01_BUILDSERVICE_OBS($username,$password,$bs));
}
/**
* Return an array with an instance of the OCS abstractor for all the remote accounts
* for the specified user
* @param string $user
* @param int $userdb
* @return array An array containing an instance of the H01_BUILDSERVICE_OCS class for each remote publisher account for the specified user
*/
static function getpublishersforuser($user,$userdb) {
$instances=array();
$accts=H01_BUILDSERVICE::remoteaccountslist($user,$userdb);
foreach($accts['remoteaccountslist'] as $account) {
// Only do this for build services, obviously...
if($account['type']==2) {
$pub=NULL;
foreach(H01_BUILDSERVICE::$PUBLISHERS as $key => $temppublisher) {
if($temppublisher['id']==$account['typeid']) {
$pub=& H01_BUILDSERVICE::$PUBLISHERS[$key];
break;
}
}
$datafield=array();
if(strlen($account['data'])>0) {
$datafield=unserialize($account['data']);
}
$instances[$account['id']]=new H01_BUILDSERVICE_OCS($account['login'],$account['password'],$datafield,$pub);
}
}
return($instances);
}
// Build Services section
/**
* Get a list of all the build services available. If the user is not authenticated the complete
* list of services is returned. If the user is authenticated the list is returned of build
* services that user is signed up for.
* @param string $user
* @param int $userdb
* @return array An array, which contains buildservice data, of the form: id=>array()
*/
static function buildserviceslist($user,$userdb){
$capa=array();
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key=>$bs ) {
$c=array();
$c['id']=$bs['id'];
$c['name']=$bs['name'];
$c['registrationurl']=$bs['registrationurl'];
foreach($bs['supportedtargets'] as $key2=>$targetData){
$c['supportedtargets'][]=array('id'=>$targetData['id'],'name'=>$targetData['name']);
}
$capa[]=$c;
}
return(array("buildservices"=>$capa));
}
/**
* Get a list of all the build services available. If the user is not authenticated the complete
* list of services is returned. If the user is authenticated the list is returned of build
* services that user is signed up for.
* @param string $user
* @param int $userdb
* @param string $buildserviceID
* @return array An array, which contains buildservice data, of the form: id=>array()
*/
static function buildservicesget($user,$userdb,$buildserviceID){
$capa=array();
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key=>$bs ) {
if($buildserviceID==$bs['id']){
$capa['id']=$bs['id'];
$capa['name']=$bs['name'];
$capa['registrationurl']=$bs['registrationurl'];
foreach($bs['supportedtargets'] as $key2=>$targetData){
$capa['supportedtargets'][]=array('id'=>$targetData['id'],'name'=>$targetData['name']);
}
break;
}
}
return(array('buildservice'=>$capa));
}
// Build Jobs section
/**
* Get a list of jobs pertaining to one project on the build service
* @param string $user
* @param int $userdb
* @param int $projectID
* @return array A list of jobs connected to the project
*/
static function jobslist($user,$userdb,$projectID){
$joblist=array();
$failure=false;
if(is_numeric($projectID)) {
$result=H01_DB::select('buildservice_projects','user,userdb,name,version,license,url,developers,summary,description,requirements,specfile,changed from buildservice_projects where id="'.addslashes($projectID).'"');
$data=H01_DB::fetch_assoc($result);
H01_DB::free_result($result);
if(count($data)>0){
if($data['user']==$user and $data['userdb']==$userdb){
// Yay, user is the right one and all that jazz!
$result2=H01_DB::select('buildservice_projects','id,projectid,buildservice,target,name,status,progress,url,message from buildservice_jobs where projectid='.addslashes($projectID).' and user="'.addslashes($user).'" and userdb='.$userdb);
$count=H01_DB::numrows($result2);
for($i=0;$ibuildstatus($projectdata,$jobdata['target']);
$item['progress']=$jobinfo['progress'];
$item['status']=$jobinfo['status'];
$item['message']=$jobinfo['message'];
} else {
$item['message']='Failed to contact build service for further information. The build service the project is tied to ('.$jobdata['buildservice'].') does not exist. This may be due to a change in service configuration.';
}
$joblist[]=$item;
}
} else {
$failure=array('code'=>101,'message'=>'no such project');
}
} else {
$failure=array('code'=>101,'message'=>'no such project');
}
} else {
$failure=array('code'=>102,'message'=>'project id should be an int');
}
if($failure) {
return($failure);
}
return(array("buildjobs"=>$joblist));
}
/**
* Create a new build job for a specified project, on a specified build service, with a specified
* target
* @param int $projectID
* @param int $buildserviceID
* @param string $target
* @param string $user
* @param int $userdb
* @return array A one-dimensional array with buildjobid=>value where value is the if of the created build job, or on failure
*/
static function jobscreate($projectID,$buildserviceID,$target,$user,$userdb){
$jobID=NULL;
$failure=false;
$result=H01_DB::select('buildservice_projects','user,userdb,name from buildservice_projects where id="'.addslashes($projectID).'"');
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
if($data['user']==$user and $data['userdb']==$userdb){
$found=false;
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key=>$value){
if($buildserviceID==$value['id']){
$targetID='none';
$targetName='';
foreach($value['supportedtargets'] as $key2=>$bsTarget) {
if($target==$bsTarget['id']){
$targetID=$bsTarget['id'];
$targetName=$bsTarget['name'];
}
}
if(is_numeric($targetID)){
$obshandler=H01_BUILDSERVICE::getbuildserviceforuser($user,$userdb,$buildserviceID);
if($obshandler===NULL) {
// Fail out if user has not added information about the build service
$failure=array('code'=>106,'message'=>'failed to create build job - user is not registered on build service. See buildservice/remoteaccounts/add');
$found=true; // while this is dubiously true, the found means that the build service exists. This is true - the user just doesn't have an account registered for it
break;
}
/// FIXME This is the most expensive operation we run and might be somewhat hammering
/// However, we also call these functions in such rapid succession that it will hardly
/// matter in any real sense
// Create the build job on the build service here, only create in database if
// successful. Otherwise return failure with all relevant information in message
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$projectID);
$buildserviceSuccess=$obshandler->addtarget($projectData,$targetID);
if($buildserviceSuccess) {
$url="http://url.to.buildservice.status/";
$name=$value['name'] . ' job for ' . $targetName;
$sqlquery='into buildservice_jobs (user,userdb,projectid,buildservice,target,name,status,progress,url,message,output,changed) values(';
$sqlquery.="\"$user\",$userdb,";
$sqlquery.='"' . addslashes($projectID) . '",';
$sqlquery.='"' . addslashes($buildserviceID) . '",';
$sqlquery.='"' . addslashes($targetID) . '",';
$sqlquery.='"' . addslashes($name) . '",';
$sqlquery.='"running",';
$sqlquery.='0.0,';
$sqlquery.='"' . addslashes($obshandler->buildinfourl($projectData,$targetID)) . '",';
$sqlquery.='"message for the build job '.$name.'",';
$sqlquery.='"output from the build job '.$name.'",';
$sqlquery.='"'.time().'")';
$result = H01_DB::insert('buildservice_jobs',$sqlquery);
if($result){
$jobID=H01_DB::insertid();
H01_DB::free_result($result);
} else {
$failure=array('code'=>106,'message'=>'failed to create build job - database access failure');
}
} else {
$failure=array('code'=>106,'message'=>'Failed to create build job. '.$obshandler->errorMessage());
}
} else {
if(is_numeric($target)) {
$failure=array('code'=>105,'message'=>'build service does not support target');
} else {
$failure=array('code'=>105,'message'=>'build service does not support target- the target ID should be an integer');
}
}
$found=true;
break;
}
}
if($found===false) {
$failure=array('code'=>103,'message'=>'no such build service');
}
} else {
// Not technically correct, but the /user/ has no such project at any rate
$failure=array('code'=>101,'message'=>'no such project');
}
} else {
$failure=array('code'=>101,'message'=>'no such project');
}
H01_DB::free_result($result);
if($failure)
return($failure);
return(array('buildjobid'=>$jobID));
}
/**
* Cancel a specified build job
* @param int $buildjobID
* @param string $user
* @param int $userdb
* @return bool True if the build job was successfully cancelled, otherwise false
*/
static function jobscancel($buildjobID,$user,$userdb){
$success=false;
if(is_numeric($buildjobID)){
$result=H01_DB::select('buildservice_jobs','id,projectid,buildservice,target from buildservice_jobs where id='.addslashes($buildjobID).' and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
H01_DB::free_result($result);
// Get project data
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$data['projectid']);
// Inform build service to remove the target - this will stop the build and reschedule all builds
$obshandler=H01_BUILDSERVICE::getbuildserviceforuser($user,$userdb,$data['buildservice']);
// Attempt to cancel build job on build service server
$buildserviceSuccess=$obshandler->removetarget($projectData,$data['target']);
// Remove from DB if successful, otherwise return failure
if($buildserviceSuccess) {
$result=H01_DB::delete('buildservice_jobs','from buildservice_jobs where id='.addslashes($buildjobID));
$success=true;
}
}
H01_DB::free_result($result);
}
return($success);
}
/**
* Get information about a specified build job
* @param string $user
* @param int $userdb
* @param int $buildjobID
* @return array A one-dimensional array containing information about a build job
*/
static function jobsget($buildjobID,$user,$userdb){
$bjdata=array();
if(is_numeric($buildjobID)){
$result=H01_DB::select('buildservice_jobs','projectid,buildservice,target,name,status,progress,url,message from buildservice_jobs where id='.addslashes($buildjobID).' and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
$bjdata['id']=$buildjobID;
$bjdata['project']=$data['projectid'];
$bjdata['buildservice']=$data['buildservice'];
$bjdata['target']=$data['target'];
$bjdata['name']=$data['name'];
$bjdata['url']=$data['url'];
///TODO These items should probably not be stored in the database... But they're there for now
$bjdata['status']=$data['status'];
$bjdata['progress']=$data['progress'];
$bjdata['message']=$data['message'];
$obshandler=H01_BUILDSERVICE::getbuildserviceforuser($user,$userdb,$data['buildservice']);
if($obshandler) {
$projectdata=H01_BUILDSERVICE::projectget($user,$userdb,$data['projectid']);
$jobinfo=$obshandler->buildstatus($projectdata,$data['target']);
$bjdata['progress']=$jobinfo['progress'];
$bjdata['status']=$jobinfo['status'];
$bjdata['message']=$jobinfo['message'];
$bjdata['url']=$jobinfo['url'];
} else {
$bjdata['message']='Failed to contact build service for further information.';
}
}
H01_DB::free_result($result);
}
return(array('buildjob'=>$bjdata));
}
/**
* Get the command output from a specified build job
* @param int $buildjobID
* @param int $userdb
* @param int $buildjobID
* @return array A one-dimensional array of the form output=>value, where value is either the string of output, or NULL in the case of failure
*/
static function jobsgetoutput($buildjobID,$user,$userdb){
$output=NULL;
if(is_numeric($buildjobID)){
$result=H01_DB::select('buildservice_jobs','projectid,buildservice,target,output from buildservice_jobs where id='.addslashes($buildjobID).' and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
$output=$data['output'];
$obshandler=H01_BUILDSERVICE::getbuildserviceforuser($user,$userdb,$data['buildservice']);
if($obshandler) {
$projectdata=H01_BUILDSERVICE::projectget($user,$userdb,$data['projectid']);
$output=$obshandler->buildlog($projectdata,$data['target']);
}
}
H01_DB::free_result($result);
}
return(array('output'=>$output));
}
// Publishing section
/**
* Get a list of supported publishers, optionally for the currently authorised user
* @param string $user
* @param int $userdb
* @return array An array containing publisher data
*/
static function publishinggetpublishingcapabilities($user,$userdb){
$publishers=array();
$data=''; // Dummy variable, this isn't really used, but it's required none the less
foreach(H01_BUILDSERVICE::$PUBLISHERS as $key=>$value) {
$publisher=array();
$publisher['id']=$key;
$publisher['name']=$value['name'];
$publisher['registrationurl']=$value['registrationurl'];
$ocsInstance=NULL;
foreach($value['fields'] as $key2 => $field) {
$publisher['fields'][$key2]=$field;
if(!is_array($field['options'])) {
if($ocsInstance==NULL) {
$ocsInstance=new H01_BUILDSERVICE_OCS(NULL,NULL,$data,$value);
}
$publisher['fields'][$key2]['options']=array_values($ocsInstance->getitemlist($field['options']));
}
}
foreach($value['targets'] as $key2 => $target2) {
$publisher['supportedtargets'][]=$key2;
}
$publishers[]=$publisher;
}
return(array('publishers'=>$publishers));
}
/**
* Get information on a specified publisher
* @param int $publisherID
* @return array An array containing publisher data, in the form publisher=>array()
*/
static function publishinggetpublisher($publisherID){
$publisher=NULL;
if(array_key_exists($publisherID,H01_BUILDSERVICE::$PUBLISHERS)){
$publisher['id']=$publisherID;
$publisher['name']=H01_BUILDSERVICE::$PUBLISHERS[$publisherID]['name'];
$publisher['registrationurl']=H01_BUILDSERVICE::$PUBLISHERS[$publisherID]['registrationurl'];
$ocsInstance=NULL;
$data=''; // Dummy variable, this isn't really used, but it's required none the less
foreach(H01_BUILDSERVICE::$PUBLISHERS[$publisherID]['fields'] as $key2 => $field) {
$publisher['fields'][$key2]=$field;
if(!is_array($field['options'])) {
if($ocsInstance==NULL) {
$ocsInstance=new H01_BUILDSERVICE_OCS(NULL,NULL,$data,H01_BUILDSERVICE::$PUBLISHERS[$publisherID]);
}
$publisher['fields'][$key2]['options']=array_values($ocsInstance->getitemlist($field['options']));
}
}
foreach(H01_BUILDSERVICE::$PUBLISHERS[$publisherID]['targets'] as $key => $target) {
$publisher['supportedtargets'][]=$key;
}
}
return(array('publisher'=>$publisher));
}
/**
* Publish the result of a bulid job on some specified project to a publisher
* @param int $buildjobID
* @param int $publisherID
* @param string $user
* @param int $userdb
* @return bool True if the publishing was successfully completed, false if not
*/
static function publishingpublishtargetresult($buildjobID,$publisherID,$user,$userdb){
$success=false;
if(array_key_exists($publisherID,H01_BUILDSERVICE::$PUBLISHERS)){
if(is_numeric($buildjobID)){
$result=H01_DB::select('buildservice_jobs','id,buildservice,target,projectid from buildservice_jobs where id='.addslashes($buildjobID).' and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
$buildservice=0;$buildserviceID=0;
foreach(H01_BUILDSERVICE::$BUILDSERVICES as $key=>$value) {
if($data['buildservice']==$value['id']) {
$buildservice=$key;
$buildserviceID=$value['id'];
break;
}
}
$buildTarget='';
foreach(H01_BUILDSERVICE::$BUILDSERVICES[$buildservice]['supportedtargets'] as $targetKey=>$searchTarget) {
if($data['target']==$searchTarget['id']){
$buildTarget=$searchTarget;
break;
}
}
// Grab the project data for the project associated with this build
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$data['projectid']);
// Get the packages resulting from the build job and run through them all, checking
// whether we should actually be publishing them (in other words, not publishing the
// source packages)
$bsHandler=H01_BUILDSERVICE::getbuildserviceforuser($user,$userdb,$buildserviceID);
$packages=$bsHandler->packagelist($projectData,$buildTarget['id']);
if(is_array($packages) && count($packages)>0) {
$fields=H01_BUILDSERVICE::publishinggetfields($data['projectid'],$user,$userdb);
$publishers=H01_BUILDSERVICE::getpublishersforuser($user,$userdb);
foreach($packages as $package) {
if($package['source']==true) {
// Skip source packages, only publish the binaries directly
continue;
}
// Run through all the publishers we've got and push the packages to them all, when
// appropriate.
foreach($publishers as $publisher) {
$thePublisher=$publisher->publisher();
foreach($thePublisher['targets'] as $pubTargetKey => $pubTarget) {
if($pubTarget['repository']==$buildTarget['repository'] && $pubTarget['arch']==$buildTarget['arch']) {
$publisher->publishpackage($projectData,$fields,$package['url'],$pubTargetKey);
break;
}
}
}
// Yes, this means running the loop twice - but data saving is expensive enough that
// we really shouldn't be doing it too often, so...
foreach($publishers as $id => $publisher) {
if($publisher->hasDataChanged()) {
H01_BUILDSERVICE::remoteaccountsedit($user,$userdb,$id,NULL,NULL,serialize($publisher->data()));
}
}
}
$success=true;
} else {
$success=array('code'=>108,'message'=>'publishing failed (no packages exist for the build job which could be published)');
}
} else {
$success=array('code'=>103,'message'=>'no such build job');
}
H01_DB::free_result($result);
} else {
$success=array('code'=>105,'message'=>'build job id should be an integer');
}
} else {
if(is_numeric($publisherID))
$success=array('code'=>106,'message'=>'no such publisher');
else
$success=array('code'=>107,'message'=>'publisher id should be an integer');
}
return($success);
}
/**
* Save some field data (as connected to publishing the project) into that project
* @param int $projectID
* @param array $fields A bunch of field data, in the form
* array(array("name"=>value,"fieldtype"=>value,"data"=>value))
* @param string $user
* @param int $userdb
* @return bool True if the save was successfully completed, array with fault information if not: array('code'=>error code,'message'=>'error description')
*/
static function publishingsavefields($projectID,$fields,$user,$userdb){
$success=false;
$result=H01_DB::select('buildservice_projects','publishingfields from buildservice_projects where id="'.addslashes($projectID).'" and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
$dbfields=unserialize($data['publishingfields']);
// This is a bit ugly, but needed to ensure a bit of sanity...
// Projects are created simply with no data in this field, so...
if(!is_array($dbfields))
$dbfields=array();
// Actually fill up the data
foreach($fields as $key => $field) {
$dbfields[ $field['name'].'-'.$field['fieldtype'] ]=array('name'=> $field['name'], 'fieldtype'=>$field['fieldtype'], 'data'=>$field['data']);
}
$updateFields=array('publishingfields'=>'"'. addslashes(serialize($dbfields)) . '"');
$clauses='where id="'.addslashes($projectID).'"';
$updateStatement=H01_BUILDSERVICE::buildupdatestatement('buildservice_projects', $updateFields, $clauses);
H01_DB::free_result($result);
$result=H01_DB::update('buildservice_projects', $updateStatement);
// Now, if we have any registered publishers, tell those all our wonderful new infos!
$publishers=H01_BUILDSERVICE::getpublishersforuser($user,$userdb);
$projectData=H01_BUILDSERVICE::projectget($user,$userdb,$projectID);
$tmpFields=array('fields'=>$dbfields);
foreach($publishers as $id => $publisher) {
$publisher->updatepublishedfields($projectData,$tmpFields);
if($publisher->hasDataChanged()) {
H01_BUILDSERVICE::remoteaccountsedit($user,$userdb,$id,NULL,NULL,serialize($publisher->data()));
}
}
$success=true;
} else {
// While it is not technically correct that there is no such project when it's an incorrect
// user, it is correct that that user has no such project...
if(is_numeric($projectID))
$success=array('code'=>101,'message'=>'no such project');
else
$success=array('code'=>102,'message'=>'project id should be an integer');
}
H01_DB::free_result($result);
return($success);
}
/**
* Get all the saved fields for some specified project
* @param string $user
* @param int $userdb
* @param int $projectID
* @return array A two-dimensional array containing field data in the form array( array("name"=buildservice>value,"fieldtype"=>value,"data"=>value), array(...))
* In the case of an error, there will be a one-dimensional array with the keys 'code' and 'message' in stead
*/
static function publishinggetfields($projectID,$user,$userdb){
$success=false;
$result=H01_DB::select('buildservice_projects','publishingfields from buildservice_projects where id="'.addslashes($projectID).'" and user="'.addslashes($user).'" and userdb='.addslashes($userdb));
$data=H01_DB::fetch_assoc($result);
if(count($data)>0){
$dbfields=unserialize($data['publishingfields']);
// This is a bit ugly, but needed to ensure a bit of sanity...
if(!is_array($dbfields))
$dbfields=array();
// Just a bit of transformation, as we're not actually exposing the internal keys to the outside world...
$success=array_values($dbfields);
} else {
// While it is not technically correct that there is no such project when it's an incorrect
// user, it is correct that that user has no such project...
if(is_numeric($projectID))
$success=array('code'=>101,'message'=>'no such project');
else
$success=array('code'=>102,'message'=>'project id should be an integer');
}
H01_DB::free_result($result);
if(array_key_exists('code',$success))
return($success);
return(array("fields"=>$success));
}
/**
* Check if fileuploads are correct
*
* @param Uploadfile $filename
* @param first filesize $filesize1
* @param second filesize $filesize2
* @param maximum upload size $maxfilesize
*/
static function checkfileupload($filename,$filesize1,$filesize2,$maxfilesize) {
$ext=strtolower(H01_UTIL::getfileext(basename($filename)));
if ($ext<>'zip' and $ext<>'tgz' and $ext<>'tar' and $ext<>'bz2' and $ext<>'gz') {
return('The file "'.$filename.'" is invalid. The filetype must be *.zip, *.tgz, *.tar, *.bz2 or *.gz');
}
if ($filesize1<>$filesize2) {
return('The Upload of the file "'.$filename.'" was not successful. Please try again.');
}
if ($filesize1>$maxfilesize) {
return('The file "'.$filename.'" is too big. Please try again.');
}
return('');
}
/**
* Attempt to generate a new skeleton specfile from the uploaded source archive
* @param array project An array of projectdata as returned by H01_BUILDSERVICE::projectget()
* @return string The newly generated spec file
*/
static function generatenewspecfile($projectdata) {
$currentdate=date('D M d Y');
$projectID=$projectdata['project']['projectid'];
$projectname=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectversion=$projectdata['project']['version'];
$projectlicense=$projectdata['project']['license'];
///TODO This is obviously wrong, but we'll have to live with it for now...
$projectsourceextension=".zip";
$projectgroup='Insert group name here!';
$projecturl=$projectdata['project']['url'];
$projectsummary=$projectdata['project']['summary'];
$projectdescription=$projectdata['project']['description'];
///TODO This is obviously wrong, but... well, it works for now :P
$authoremail=explode("\n",$projectdata['project']['developers'],1);
$authoremail=$authoremail[0];
// Attempt to use the obs generator, by filling out the INFO file and then running the tool
$projectdir=CONFIG_DOCUMENT_ROOT.'/CONTENT/buildservice-files/'.$projectID.'/';
$infocontents="RPM_GROUP: Productivity
DEB_SECTION: utils
DEVELOPERS: $authoremail
LICENSE: $projectlicense
URL: $projecturl
SUMMARY: $projectsummary
DESCRIPTION:
$projectdescription
END_DESCRIPTION";
// if(file_exists($projectdir.'INFO')) {
// unlink($projectdir.'INFO');
// }
// file_put_contents($projectdir.'INFO',$infocontents);
// $cmdOutput=array();
// $cmdReturn=0;
// chdir($projectdir); // ensure we're running the tool in the project directory...
// exec('obs-generator',$cmdOutput,$cmdReturn);
// // Did this yield a spec file? If so, return the data from that file
// if($cmdReturn==0) {
// // If obs-generator fails for some reason, it will in its current shape return 1.
// // In the future this will possibly change to support multiple return values, but for now
// // all errors are reported as simply a 1. So, if we get a 0, we had a successful attempt.
// if(file_exists($projectdir.$projectname.'.spec')) {
// // While we know the process ended successfully, let's just make sure the file is actually
// // there before we pass it back anyway
// return(file_get_contents($projectdir.$projectname.'.spec'));
// }
// }
// This is a random spec file which which we can sort of use if obs-generator fails
$specfile="Name: $projectname
# List of additional build dependencies - the following are examples and you will likely want to change them
BuildRequires: cmake gcc-c++ libqt4-devel unzip
Version: $projectversion
Release: 1
License: $projectlicense
Source: %{name}-%{version}$projectsourceextension
Group: $projectgroup
Summary: $projectsummary
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
$projectdescription
%prep
# Use this command if your source package contains a versioned folder structure
# %setup -q -n %{name}-%{version}
%setup -q -n %{name}
%build
# Assume that the package is built by plain 'make' if there's no ./configure or cmake.
if test -e ./CMakeLists.txt; then
cmake -DCMAKE_INSTALL_PREFIX=/usr .
elif test -x ./configure; then
%configure
elif test -e ./%{name}.pro; then
qmake -set PREFIX %{buildroot}/usr
qmake
fi
make
%install
# This is a hack to ensure a proper install target is created.
# See http://bugreports.qt.nokia.com/browse/QTBUG-5558
if test -e ./%{name}.pro; then
qmake
fi
make DESTDIR=%buildroot install
# Write a proper %%files section and remove these two commands and
# the '-f filelist' option to %%files
echo '%%defattr(-,root,root)' >filelist
find %buildroot -type f -printf '/%%P*\n' >>filelist
%clean
rm -rf %buildroot
%files -f filelist
%defattr(-,root,root)
# This is a place for a proper filelist:
# /usr/bin/$projectname
# You can also use shell wildcards:
# /usr/share/$projectname/*
# This installs documentation files from the top build directory
# into /usr/share/doc/...
# %doc README COPYING
# The advantage of using a real filelist instead of the '-f filelist' trick is
# that rpmbuild will detect if the install section forgets to install
# something that is listed here
%changelog
* $currentdate $authoremail
- packaged $projectname version $projectversion using the Open Collaboration Services OBS Interface";
return($specfile);
}
}
/// \brief Simplified acessor class for the openSuse Build Service
class H01_BUILDSERVICE_OBS {
private $username;
private $password;
private $buildservice;
/// @var string The URL of the build service API
private $buildserviceapiurl;
/// @var string The project used to handle build jobs from the current user. This is the full path
private $project;
/// @var cURLhandle The curl handle used for all access to the remote service until destruction
private $ch;
/// @var string The last error message returned by the system. This will be filled with the error message when the buildservice returns an error for some function.
private $lasterrormessage='';
function errorMessage() {
return $this->lasterrormessage;
}
function __construct($username, $password, &$buildservice) {
$this->username=$username;
$this->password=$password;
$this->buildservice=&$buildservice;
$this->buildserviceapiurl=$buildservice['apiurl'];
$this->project='home:'.$username.':ocs-buildservice';
// check if curl is available
if (!function_exists("curl_init")) {
print "I cannot continue because Curl doesn't exist. Sorry.\n";
exit;
}
// check if simplexml is available
if (!function_exists("simplexml_load_string")) {
print "I cannot continue because SimpleXML doesn't exist. Sorry.\n";
exit;
}
// setup curl
$curl_opts = array
(
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_USERPWD => $username . ':' . $password,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_USERAGENT => 'OCSOBSModule/v1.0',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_UNRESTRICTED_AUTH => true
);
$this->ch = curl_init();
curl_setopt_array($this->ch, $curl_opts);
}
function __destruct() {
if (function_exists("curl_close")) {
curl_close($this->ch);
}
/// TODO Add some cleanup logic to ensure we have shut down all the connections properly and give error messages when that is not the case
}
/**
* Perform a GET call on the service
* @param string command The command you wish to call on the service
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doGET($command,$arguments=array()) {
$urlargs='';
if(count($arguments)) {
$urlargs='?' . http_build_query($arguments);
}
curl_setopt($this->ch, CURLOPT_URL, $this->buildserviceapiurl . $command . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, array());
curl_setopt($this->ch, CURLOPT_POST, false);
curl_setopt($this->ch, CURLOPT_PUT, false);
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
return($res);
}
/**
* Perform a POST call on the service
* @param string command The command you wish to call on the service
* @param array postdata An array containing the post fields
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doPOST($command,$postdata=array(),$arguments=array()) {
$urlargs=http_build_query($arguments);
curl_setopt($this->ch, CURLOPT_URL, $this->buildserviceapiurl . $command . '?' . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($this->ch, CURLOPT_POST, true);
curl_setopt($this->ch, CURLOPT_PUT, false);
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
return($res);
}
/**
* Perform a PUT call on the service
* @param string command The command you wish to call on the service
* @param string putdata The string containing the data to be pushed to the service
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doPUT($command,$putdata='',$arguments=array()) {
$urlargs=http_build_query($arguments);
curl_setopt($this->ch, CURLOPT_URL, $this->buildserviceapiurl . $command . '?' . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, array());
curl_setopt($this->ch, CURLOPT_POST, false);
curl_setopt($this->ch, CURLOPT_PUT, true);
$putfile = tmpfile();
fwrite($putfile, $putdata);
fseek($putfile, 0);
curl_setopt($this->ch, CURLOPT_INFILE, $putfile);
curl_setopt($this->ch, CURLOPT_INFILESIZE, strlen($putdata));
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
// Gotta do this after curl_exec, as setting the option doesn't execute the file read ;)
fclose($putfile);
return($res);
}
/**
* Perform a PUT call on the service, pushing an existing file
* @param string command The command you wish to call on the service
* @param string putfile A string containing the filename for the file to be pushed
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doPUTFile($command,$putfile,$arguments=array()) {
$urlargs=http_build_query($arguments);
curl_setopt($this->ch, CURLOPT_URL, $this->buildserviceapiurl . $command . '?' . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, array());
curl_setopt($this->ch, CURLOPT_POST, false);
curl_setopt($this->ch, CURLOPT_PUT, true);
$file=fopen($putfile,'r');
curl_setopt($this->ch, CURLOPT_INFILE, $file);
curl_setopt($this->ch, CURLOPT_INFILESIZE, filesize($putfile));
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
// Gotta do this after curl_exec, as setting the option doesn't execute the file read ;)
fclose($file);
return($res);
}
/**
* Perform a DELETE call on the service, asking for the deletion of some item
* @param string command The name of the file you wish to delete
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doDELETE($command,$arguments) {
$urlargs=http_build_query($arguments);
curl_setopt($this->ch, CURLOPT_URL, $this->buildserviceapiurl . $command . '?' . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, array());
curl_setopt($this->ch, CURLOPT_POST, false);
curl_setopt($this->ch, CURLOPT_PUT, false);
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
// Reset this option in here, as the DELETE command is... somewhat odd anyway. Yay for non-
// standard HTTP requests! ;)
curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, null);
return($res);
}
/**
* Attempt to access the user's project and simply touch it. If the ocs-buildservice sub-project
* does not exist, it is created. This call will only fail if the service is unreachable for some
* reason (such as for example the user not being registered at all)
* @return bool True if successful, otherwise false
*/
private function accesstest() {
/// TODO Unfortunately it would be unwise to cache this result for longer than a few seconds, but
/// at least, i guess, we can actually do that :) Will help greatly when we are throwing lots and
/// lots of jobs off to the services
// Attempt to dig into the ocs-buildservice project
$result=$this->doGET('source/' . $this->project . '/_meta');
if($this->curl_info['http_code']==401 || $result==false) {
$this->lasterrormessage='Could not log in with the saved user credentials. Please check your user login and try again. If you have not yet registered for this build service, please do so by visiting the address '. $this->buildservice['registrationurl'];
return(false);
}
$xml = new SimpleXMLElement($result);
// If it does not exist, create it and try again
$attrs=$xml->attributes();
if(isset($attrs['code']) && (string)$attrs['code']=='unknown_project'){
// Comment originally for the single project template - still applies though storing it here now
// A bit of an ugly one, but it saves inlining, which is even more ugly
// Also, the list of repositories here should not be hardcoded in this manner - however, we're now
// officially in a hurry, so hardcoding it is.
// We're adding every repository on the planet to this, and then telling the build service to not
// build any at all. This allows us to set it per-obs-package (per-ocs-project) much easier
$this->doPUT('source/' . $this->project . '/_meta', str_replace('USERNAME', $this->username, $this->buildservice['projectTemplate']) );
} else {
// It worked! Yay,
return(true);
}
$result=$this->doGET('source/' . $this->project . '/_meta');
$xml = new SimpleXMLElement($result);
$attrs=$xml->attributes();
if(isset($attrs['code']) && (string)$attrs['code']=='unknown_project'){
// Ohnoes, we have failed!
$this->lasterrormessage='Could not create a new project in the build service to create software packages inside. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
return(false);
}
// It worked! Yay,
return(true);
}
/**
* Return a normalized version of the project's name, for use as a package name on the build
* service.
* @param string projectName The name you wish to have normalized
* @return string The equalised project name
*/
public static function normalizeProjectName($projectName) {
return strtolower(str_replace(' ', '_', $projectName));
}
/**
* In OCS Buildservice terminology, a project is equivalent to the OBS term package
* The reason we have the difference is that our projects are one-to-one related to for example
* a Qt Creator project. And from one such project you would create a single spec sheet (source
* package) from which several finary packages are then created.
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @return bool True on success, false on failure
* @see H01_BUILDSERVICE::projectget
*/
public function storeproject($projectdata) {
if(!$this->accesstest()) {
return false;
}
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectMetaFile='source/' . $this->project . '/' . $projectName . '/_meta';
$projectSpecFile='source/' . $this->project . '/' . $projectName . '/' . $projectName . '.spec';
// Attempt to load an existing package by the same name
$project=$this->doGET($projectMetaFile);
$project=new SimpleXMLElement($project);
// If unsuccessful, create that package
$projAttrs=$project->attributes();
if(isset($projAttrs['code']) && (string)$projAttrs['code']=='404'){
$project=H01_BUILDSERVICE_OBS::$packageTemplate;
$project=str_replace('USERNAME',$this->username,$project);
$project=str_replace('PACKAGENAME',$projectName,$project);
if(array_key_exists('name',$projectdata['project'])) {
$project=str_replace('PACKAGETITLE',$projectdata['project']['name'],$project);
}
if(array_key_exists('description',$projectdata['project'])) {
$project=str_replace('PACKAGEDESCRIPTION',$projectdata['project']['description'],$project);
}
if(!$this->doPUT($projectMetaFile,$project)) {
// Dropping out here is a little nasty, but if we for some reason fail to write the project,
// we really need to fail out here
$this->lasterrormessage='Failed to create the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
return(false);
}
$project=new SimpleXMLElement($project);
}
// Add new information as found in the project data array
if(array_key_exists('name',$projectdata['project'])) {
$project->title=$projectdata['project']['name'];
}
if(array_key_exists('description',$projectdata['project'])) {
$project->description=$projectdata['project']['description'];
}
if(array_key_exists('url',$projectdata['project'])) {
$project->url=$projectdata['project']['url'];
}
// Store package back onto service
$success=$this->doPUT($projectMetaFile,$project->asXML());
if($success) {
// This needs special handling
if(array_key_exists('specfile',$projectdata['project'])) {
$success=$this->doPUT($projectSpecFile,$projectdata['project']['specfile']);
if($success==false) {
$this->lasterrormessage='Failed to save the spec file to the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
}
} else {
$this->lasterrormessage='Failed to save new data to the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
return($success);
}
/**
* Attempt to delete the package representing the passed project on the build service
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @return bool True on success, false on any failure
*/
public function deleteproject($projectdata) {
if(!$this->accesstest()) {
return false;
}
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectNameOnServer='source/' . $this->project . '/' . $projectName;
$success=$this->doDELETE($projectNameOnServer);
if($success==false) {
$this->lasterrormessage='Failed to delete the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
return($success);
}
/**
* Upload a source file to the package repository associated with the passed project data instance
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string localfile The filename for the local file which is to be uploaded
* @return bool True on success, false on any failure
*/
public function uploadsourcefile($projectdata,$localfile,$remotefilename) {
if(!$this->accesstest()) {
return false;
}
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectUploadFile='source/' . $this->project . '/' . $projectName . '/' . $remotefilename;
$success=$this->doPUTFile($projectUploadFile,$localfile);
if($success==false) {
$this->lasterrormessage='Failed to upload a new source file to the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
return($success);
}
/**
* Add the specified build target to the OBS project tied to the project represented by the
* passed project data instance.
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string target The target ID as found in the buildservice description
* @return bool True on success, false on any failure
*/
public function addtarget($projectdata,$target) {
if(!$this->accesstest()) {
return false;
}
// Technically we're doing this by simply enabling it explicitly, as all targets are specified
// in the projct, and thus we add build targets by enabling them directly
// Load package from buildservice server
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectMetaFile='source/' . $this->project . '/' . $projectName . '/_meta';
// Attempt to load an existing package by the same name
$projecttxt=$this->doGET($projectMetaFile);
$project=simplexml_load_string($projecttxt);
$projAttrs=$project->attributes();
if(isset($projAttrs['code']) && (string)$projAttrs['code']=='404'){
// If we can't get the project, fail out completely
if(!$this->storeproject($projectdata)) {
return(false);
}
}
$addRepo=$this->buildservice['supportedtargets'][$target]['repository'];
$addArchitecture=$this->buildservice['supportedtargets'][$target]['arch'];
$buildinfo=NULL;
foreach($project->children() as $child) {
if($child->getName()=='build') {
$buildinfo=$child;
break;
}
}
if($buildinfo===NULL) {
$buildinfo=$project->addChild('build');
}
// Check whether target is already there, and if so, bail out. This ensures that duplicate
// entries are not created in the database.
foreach($project->build->children() as $child) {
if(isset($child['repository']) && (string)$child['repository']==$addRepo) {
if(isset($child['arch']) && (string)$child['arch']==$addArchitecture) {
$this->lasterrormessage='Could not add target to the build list, as it is already listed in the build list of the build service project. If you feel this is in error, please visit the project via the build service web interface and disable it that way.';
return(false);
}
}
}
// If that is not the case, add the target to the build section
$newTarget=$project->build->addChild('enable');
$newTarget->addAttribute('repository',$addRepo);
$newTarget->addAttribute('arch',$addArchitecture);
// Save package back onto service
$result=$this->doPUT($projectMetaFile,$project->asXML());
if($result===false) {
$this->lasterrormessage='Failed to save the project information to the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
$retval=false;
$result2=simplexml_load_string($result);
$projAttrs=$result2->attributes();
if(isset($projAttrs['code']) && (string)$projAttrs['code']=='ok'){
$retval=true;
} else {
$this->lasterrormessage='Failed to save the project information to the build service package representing your software project. The error on the server is of unknown origin. If the error persists, please contact your system adinistrator.';
if(isset($result2['details'])) {
$this->lasterrormessage='Failed to save the project information to the build service package representing your software project. The server reported the following error: ' . (string)$result2->details;
}
}
if(!$retval) {
$this->lasterrormessage="Failed to save the project information to the build service package representing your software project. The server reported the following error:\n".$result."\nThe data which was attempted saved was:\n".$project->asXML();
}
return($retval);
}
/**
* Remove the specified build target from the OBS project tied to the project represented by the
* passed project data instance.
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string target The target ID as found in the buildservice description
* @return bool True on success, false on any failure
*/
public function removetarget($projectdata,$target) {
if(!$this->accesstest()) {
return false;
}
// Technically we're doing this by just removing the reference to the target from the project,
// as all build targets are disabled by default. Doing this will remove the target from the list
// and will stop any current builds - this is a less than clean solution and will cause some
// unfortunate number of rebuilds that we really should not be doing. But, again, we are in a
// hurry and need this thing finished.
// Load package from buildservice server
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectMetaFile='source/' . $this->project . '/' . $projectName . '/_meta';
// Attempt to load an existing package by the same name
$project=$this->doGET($projectMetaFile);
$project=simplexml_load_string($project);
$buildinfo=NULL;
foreach($project->children() as $child) {
if($child->getName()=='build') {
$buildinfo=$child;
break;
}
}
if($buildinfo===NULL) {
// If we've not got a build section at all, never mind, the target's not there. See below.
return(true);
}
// Check whether target is already there
$rmRepo=$this->buildservice['supportedtargets'][$target]['repository'];
$rmArchitecture=$this->buildservice['supportedtargets'][$target]['arch'];
$found=false;
foreach($buildinfo->children() as $child) {
$attrs=$child->attributes();
//if(array_key_exists('repository',$attrs) && $attrs['repository']==$rmRepo) {
if((string)$attrs->repository==$rmRepo) {
//if(array_key_exists('arch',$attrs) && $attrs['arch']==$rmArchitecture) {
if((string)$attrs->arch==$rmArchitecture) {
// If found, remove the target and bail out of the loop
// We do it this way to avoid return statements scattered through the function..
$oNode=dom_import_simplexml($child);
$oNode->parentNode->removeChild($oNode);
$found=true;
}
}
}
// Save package back onto service
if($found) {
$success=$this->doPUT($projectMetaFile,$project->asXML());
if($success==false) {
$this->lasterrormessage='Failed to save the project information to the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
return($success);
}
return(true);
}
///TODO: This function should be the preferred method of launching builds - setting up all builds
///at the same time, so as to avoid hammering the server with multiple build job requests.
///We can phase this in at a later point in time, however, as the above hammeringness works for now.
/**
* Attempt to launch the build jobs set up for the specified project
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param array targets The targets you wish to build for (array containing IDs as found in the buildservice listing)
* @return bool True on success, false on failure
*/
public function launchbuild($projectdata,$targets) {
if(!$this->accesstest()) {
return false;
}
// Set up a couple of items we'll be needing later on
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$projectMetaFile='source/' . $this->project . '/' . $projectName . '/_meta';
// Attempt to load an existing package by the same name
$project=$this->doGET($projectMetaFile);
$project=simplexml_load_string($project);
if(array_key_exists('code',$project) && $project['code']=='unknown_project'){
// If we can't get the project, fail out completely
// The intention is that the package should be created before attempting to launch the build
// by using the storeproject function
$this->lasterrormessage='Failed to fetch the project, because it was unknown. This error likely occurs because you forgot to create the package first.';
return(false);
}
// First, clear out all the existing target specifications in the project
// Yes this is somewhat ugly, but we can't simply assume that build exists here
foreach($project->children() as $child) {
if($child->getName()=='build') {
$oNode=dom_import_simplexml($child);
$oNode->parentNode->removeChild($oNode);
break;
}
}
$buildinfo=$project->addChild('build');
// Then add all the targets again...
foreach($targets as $target) {
$addRepo=$this->buildservice['supportedtargets'][$target]['repository'];
$addArchitecture=$this->buildservice['supportedtargets'][$target]['arch'];
$newTarget=$buildinfo->addChild('enable');
$newTarget->addAttribute('repository',$addRepo);
$newTarget->addAttribute('arch',$addArchitecture);
}
// Save package back onto service - this will automatically trigger a build
$success=$this->doPUT($projectMetaFile,$project->asXML());
if($success==false) {
$this->lasterrormessage='Failed to save the project information to the build service package representing your software project. The reason for this error is unknown, but may be due to permissions for your home project. If the error persists, please contact the administrator for your build service to discover more.';
}
return($success);
}
/**
* Build a status URL which points at where the live build information for such a project/target
* combination would sit on this build service
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string target The target ID as found in the buildservice description
* @return string The URL of the build job
*/
public function buildinfourl($projectdata,$target) {
$statusURL=$this->buildservice['statusurl'];
$statusURL=str_replace('PROJECT',$this->project,$statusURL);
$statusURL=str_replace('REPOSITORY',$this->buildservice['supportedtargets'][$target]['repository'],$statusURL);
$statusURL=str_replace('ARCH',$this->buildservice['supportedtargets'][$target]['arch'],$statusURL);
$statusURL=str_replace('PACKAGE',H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']),$statusURL);
return($statusURL);
}
/**
* Fetch the build status information for the specified job
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string target The target ID as found in the buildservice description
* @return array An array of the form array('progress'=>float,'status'=>jobstatus,'message'=>string)
*/
public function buildstatus($projectdata,$target) {
if(!$this->accesstest()) {
return false;
}
// Attempt to fetch build job information
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$repoName=$this->buildservice['supportedtargets'][$target]['repository'];
$archName=$this->buildservice['supportedtargets'][$target]['arch'];
$buildStatusFile='build/' . $this->project . '/' . $repoName . '/' . $archName . '/' . $projectName . '/_status';
$status=$this->doGET($buildStatusFile);
$status=simplexml_load_string($status);
$statuscode=H01_BUILDSERVICE_JOBSTATUS_UNKNOWN;
$legend='Unknown status code';
switch($status->attributes()->code) {
// All status codes interpreted as a somehow successfully completed job
case "succeeded":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_COMPLETED;
$legend='Package has built successfully and can be used to build further packages.';
// As the package was successfully built, grab the list of binaries and append this to the legend:
$binaries=$this->doGET('build/' . $this->project . '/' . $repoName . '/' . $archName . '/' . $projectName);
$binaries=simplexml_load_string($binaries);
foreach($binaries->children() as $child) {
$attrs=$child->attributes();
$legend.="\nDetails: https://build.opensuse.org/package/binary?arch=" . $archName . '&filename='. $attrs->filename .'&package='. $projectName .'&project=' . $this->project . '&repository=' . $repoName;
$legend.="\nDirect link: http://download.opensuse.org/repositories/home:/" . $this->username . ':/ocs-buildservice/' . $repoName . '/' . $archName . '/'. $attrs->filename;
}
break;
// All status codes interpreted as a failed job
case "failed":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_FAILED;
$legend='The package does not build successfully. No packages have been created. Packages that depend on this package will be built using any previously created packages, if they exist.';
break;
case "unresolvable":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_FAILED;
$legend='The build can not begin, because required packages are either missing or not explicitly defined.';
break;
case "broken":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_FAILED;
$legend='The sources either contain no build description (eg specfile) or a source link does not work.';
break;
case "disabled":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_FAILED;
$legend='The package has been disabled from building in project or package metadata.';
break;
case "excluded":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_FAILED;
$legend='The package build has been disabled in package build description (for example in the .spec file) or does not provide a matching build description for the target.';
break;
// All status codes interpreted as a running job...
case "blocked":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='This package waits for other packages to be built. These can be in the same or other projects.';
break;
case "dispatching":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='A package is being copied to a build host. This is an intermediate state before building.';
break;
case "scheduled":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='A package has been marked for building, but the build has not started yet.';
break;
case "building":
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='The package is currently being built.';
break;
case "signing": // The package has been built and is assigned to get signed.
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='The package has been built and is assigned to get signed.';
break;
case "finished": // The package has been built and signed, but has not yet been picked up by the scheduler. This is an intermediate state prior to 'succeeded' or 'failed'.
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='The package has been built and signed, but has not yet been picked up by the scheduler. This is an intermediate state prior to "succeeded" or "failed".';
break;
case "unknown": // The scheduler has not yet evaluated this package. Should be a short intermediate state for new packages.
default:
$statuscode=H01_BUILDSERVICE_JOBSTATUS_RUNNING;
$legend='The scheduler has not yet evaluated this package. Should be a short intermediate state for new packages.';
break;
}
$furtherinfo='';
if($status->details<>'') {
$furtherinfo="\nThe server reports: ".$status->details;
}
$statusmessage=$status->attributes()->code.': ' . $legend . $furtherinfo;
$info=array('progress'=>0.0,'status'=>$statuscode,'message'=>$statusmessage,'url'=>$this->buildinfourl($projectdata,$target));
return($info);
}
/**
* Fetch the build log for the specified job
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string target The target ID as found in the buildservice description
* @return string The full build log as it exists at the time of calling
*/
public function buildlog($projectdata,$target) {
if(!$this->accesstest()) {
return false;
}
// Attempt to fetch build job information
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$repoName=$this->buildservice['supportedtargets'][$target]['repository'];
$archName=$this->buildservice['supportedtargets'][$target]['arch'];
$buildLogFile='build/' . $this->project . '/' . $repoName . '/' . $archName . '/' . $projectName . '/_log';
///TODO When there is no log file available, this returns an XML file with information to that
/// effect. Maybe we should attempt to parse and see if te xml returned is that? Future work,
/// for sure, but would be kinda nice
return($this->doGET($buildLogFile));
}
/**
* Get a list of all the packages built for the project on the passed target.
* The returned array contains arrays with the following keys:
* - filename: string, The full filename of the package
* - url: string, The download URL for the package
* - detailsurl: string, The URL for viewing more detailed information about the package on the buildservice itself
* - source: boolean, If this is true, the package contains sources rather than installable data (for example .src.rpm files)
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string target The target ID as found in the buildservice description
* @return array A collection of data as described above
*/
public function packagelist($projectdata,$target) {
if(!$this->accesstest()) {
return array();
}
// Attempt to fetch build job information
$projectName=H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']);
$repoName=$this->buildservice['supportedtargets'][$target]['repository'];
$archName=$this->buildservice['supportedtargets'][$target]['arch'];
$buildStatusFile='build/' . $this->project . '/' . $repoName . '/' . $archName . '/' . $projectName . '/_status';
$packages=array();
$binaries=$this->doGET('build/' . $this->project . '/' . $repoName . '/' . $archName . '/' . $projectName);
$binaries=simplexml_load_string($binaries);
foreach($binaries->children() as $child) {
$attrs=$child->attributes();
$isSource=false;
if(substr($attrs->filename,-8)=='.src.rpm') {
$isSource=true;
}
$packages[]=array(
'filename'=>$attrs->filename,
'url'=>'http://download.opensuse.org/repositories/home:/' . $this->username . ':/ocs-buildservice/' . $repoName . '/' . $archName . '/'. $attrs->filename,
'detailsurl'=>'https://build.opensuse.org/package/binary?arch=' . $archName . '&filename='. $attrs->filename .'&package='. $projectName .'&project=' . $this->project . '&repository=' . $repoName,
'source'=>$isSource
);
}
return($packages);
}
/**
* Create a fake OSC checkout in the project directory. This needs to happen with an instance of
* the OBS abstractor, because we need a real project to tie it up against. Inconvenient, but thus
* is the nature of osc.
* @param array projectdata The project data as retreived by the H01_BUILDSERVICE::projectget call
* @param string projectDirectory The directory containing the project's files on disk
* @return bool True on success, false on failure
*/
public function createfakecheckout($projectdata,$projectDirectory) {
if(!$this->accesstest()) {
return(false);
}
// First, let's make sure the associated osc configuration file is correct (flush and rewrite)
if(file_exists($projectDirectory.'.oscrc')) {
unlink($projectDirectory.'.oscrc');
}
file_put_contents($projectDirectory.'.oscrc',
"[general]\napiurl = ".$this->buildserviceapiurl.
'['.$this->buildserviceapiurl."]\nuser=".$this->username."\npass = ".$this->password."\n"
);
// Flush existing fake checkout if it exists - this function is likely to be called to update
// information anyway
if(file_exists($projectDirectory.'.osc')) {
H01_BUILDSERVICE::rmdir_p($projectDirectory.'.osc');
@rmdir($projectDirectory.'.osc');
}
// Make directory to store checkout data in
if(mkdir($projectDirectory.'.osc')) {
// Fill the vital files with the least required amount of data
// _files - The list of files can be empty, the generator doesn't care
file_put_contents($projectDirectory.'.osc/_files',"\n");
// _osclib_version - Just say we're version 1.0
file_put_contents($projectDirectory.'.osc/_osclib_version','1.0');
// _package - Flush the project name
file_put_contents($projectDirectory.'.osc/_package',H01_BUILDSERVICE_OBS::normalizeProjectName($projectdata['project']['name']));
// _project - Grab the project name as we know it and throw it in here
file_put_contents($projectDirectory.'.osc/_project',$this->project);
} else {
$this->lasterrormessage='Failed to create the false checkout directory. This error should only happen in extreme circumstances and is most likely caused by a problematic server setup.';
return(false);
}
return(true);
}
private static $packageTemplate = '
PACKAGETITLE
PACKAGEDESCRIPTION
';
}
/**
* \brief A simple class for pushing finished packages to OCS compliant services
* When using this class, the workflow will be something like as follows:
* - Create instance, data is passed as reference
* - Do various calls on the OCS service the instance represents
* - Check whether the data field has changed
* - If so, save the modified data back into the database
* - Destroy instance
*/
class H01_BUILDSERVICE_OCS {
private $username;
private $password;
/// @var For OCS users found in the OBS handling system, this data array contains the link between content ID in the OCS service and our own project ID
private $data;
public function data() {
return $this->data;
}
private $dataHasChanged=false;
private $publisher;
/**
* Getter for the publisher - this should only ever be set through the constructor, hence not
* simply exposing it
*/
public function publisher() {
return $this->publisher;
}
/// @var string The URL of the OCS API on the publisher's server
private $publisherapiurl;
/// @var cURLhandle The curl handle used for all access to the remote service until destruction
private $ch;
function __construct($username, $password, $data, &$publisher) {
$this->username=$username;
$this->password=$password;
$this->data=$data;
$this->publisher=&$publisher;
$this->publisherapiurl=$publisher['apiurl'];
// check if curl is available
if (!function_exists("curl_init")) {
print "I cannot continue because Curl doesn't exist. Sorry.\n";
exit;
}
// check if simplexml is available
if (!function_exists("simplexml_load_string")) {
print "I cannot continue because SimpleXML doesn't exist. Sorry.\n";
exit;
}
// setup curl
$curl_opts = array
(
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_USERAGENT => 'OCSOBSModule/v1.0',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_UNRESTRICTED_AUTH => true
);
if($username && $password) {
$curl_opts[CURLOPT_HTTPAUTH]=CURLAUTH_BASIC;
$curl_opts[CURLOPT_USERPWD]=$username . ':' . $password;
}
$this->ch = curl_init();
curl_setopt_array($this->ch, $curl_opts);
}
function __destruct() {
if (function_exists("curl_close")) {
curl_close($this->ch);
}
/// TODO Add some cleanup logic to ensure we have shut down all the connections properly and give error messages when that is not the case
}
/**
* Perform a GET call on the service
* @param string command The command you wish to call on the service
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doGET($command,$arguments=array()) {
$urlargs='';
if(count($arguments)) {
$urlargs='?' . http_build_query($arguments);
}
curl_setopt($this->ch, CURLOPT_URL, $this->publisherapiurl . $command . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, array());
curl_setopt($this->ch, CURLOPT_POST, false);
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
return($res);
}
/**
* Perform a POST call on the service
* @param string command The command you wish to call on the service
* @param array postdata An array containing the post fields
* @param array arguments An optional array of arguments
* @return mixed the string data returned by the call, or false on failure
*/
private function doPOST($command,$postdata=array(),$arguments=array()) {
$urlargs='';
if(count($arguments)) {
$urlargs='?' . http_build_query($arguments);
}
curl_setopt($this->ch, CURLOPT_URL, $this->publisherapiurl . $command . $urlargs);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, http_build_query($postdata,'','&'));
curl_setopt($this->ch, CURLOPT_POST, true);
$res = curl_exec($this->ch);
$this->curl_info = curl_getinfo($this->ch);
return($res);
}
/**
* Retrieve the contentID associated with the project represented by the passed projectdata
* instance. If the project does not already exist on the remote server, it will be created.
* @param array projectData An array of project data as returned by the H01_BUILDSERVICE::projectget function
* @param array fieldData An array of field data as returned by the H01_BUILDSERVICE::publishinggetfields function
* @param bool createIfNotFound If no contente ID is currently connected with the passed project, setting this to false will cause the function to not create a new contentID for it and in stead simply return 0
* @return int The content ID of this project on the remote server
*/
private function getcontentID($projectData,$fieldData,$createIfNotFound=true) {
// Look through data to see whether there's already an association
$contentID=0;
if(array_key_exists('contentlinks', $this->data)) {
$tmpPublisherID=$this->publisher['id'];
foreach($this->data['contentlinks'] as $projectID => $searchContent) {
if($projectID==$projectData['project']['projectid'] && $tmpPublisherID==$searchContent['publisherID']) {
$contentID=$searchContent['id'];
break;
}
}
} else {
// If we get to here, this is the very first time the data array has been used, and we
// initialise it with some empty data
$this->data['contentlinks']=array();
$this->data['downloadlinks']=array();
$this->dataHasChanged=true;
}
// Sanity check - if the content's been deleted in the meantime, don't attempt to use it.
if($contentID>0) {
$isItThere=$this->doGET('content/data/'.$contentID);
$isItThere=simplexml_load_string($isItThere);
if($isItThere->meta->statuscode==101) {
$contentID=0;
// We also clear out the downloadlinks, as they clearly no longer apply...
$this->data['downloadlinks'][$projectID]=array();
$this->dataHasChanged=true;
}
}
if($contentID==0 && $createIfNotFound) {
// If not, create a new content item on the server using field data from
// projectData['publishingfields']
$postfields=array();
// Mmm, yummy hackery - this ensures that if the user has not entered any field data, we at
// least have /some/ data there.
$postfields['name']=$projectData['project']['name'];
$postfields['type']='1'; // This *must* be defined, otherwise there's nasties in the returned xml
$postfields['version']=$projectData['project']['version'];
$postfields['homepage']=$projectData['project']['url'];
$postfields['homepagetype']='0'; // default value, for homepage homepages
$postfields['summary']=$projectData['project']['summary'];
$postfields['description']=$projectData['project']['description'];
// License needs a little fanciful handling, as they're free-text in projectData, but an item
// when handling OCS services
$postfields['license']=H01_BUILDSERVICE_OCS::licenseidbyname($projectData['project']['license']);
if($postfields['license']==0) {
$postfields['licensetext']=$projectData['project']['license'];
}
foreach($this->publisher['fields'] as $publisherfield) {
// Only fill out the required fields - everything else comes later
/// TODO yeah... this is needed for now. Once the Qt Creator plugin handles fields,
/// we can get rid of this again
//if($publisherfield['required']==true) {
$foundField=false;
foreach($fieldData['fields'] as $publishingfield) {
if($publishingfield['name']==$publisherfield['name'] && $publishingfield['fieldtype']==$publisherfield['fieldtype']) {
// If these two match, we shall argue that they are the same thing!
$fieldname=H01_BUILDSERVICE_OCS::fieldnametopostname($publishingfield['name']);
$postfields[$fieldname]=$this->fieldvaluesanitizer($publishingfield['name'],$publishingfield['fieldtype'],$publishingfield['data']);
$foundField=true;
}
//}
//if($foundField==false) {
// // If the field (which of course is required) was not found, bail out entirely, panic!
// return(0);
//}
}
}
// Post a new item with the required fields in place...
$contentreturn=$this->doPOST('content/add',$postfields);
// We may get a false back from here, so...
if($contentreturn) {
$hc=$this->curl_info['http_code'];
if($hc==100 || $hc>200 || $hc<299) {
// Load the resulting XML
$contentreturn=simplexml_load_string($contentreturn);
if((int)$contentreturn->meta->statuscode != 100) {
// Error message should probably be set here...
// echo("Error attempting to add the new content item. Error returned by server was: \n{$contentreturn->meta->message}");
return(0);
}
// Otherwise we're good - grab the data->content->id value!
$contentID=(int)$contentreturn->data->content->id;
$this->data['contentlinks'][$projectData['project']['projectid']]=array('publisherID'=>$this->publisher['id'],'id'=>$contentID);
$this->dataHasChanged=true;
} else {
// This will happen on wrong username and a few other things... not a good thing, but
// whatever causes it, it means we've got the wrong data and specifically not got a
// content ID to report back
return(0);
}
}
// Finally, update all the fields, just to be completely sure
// This may look as though it would potentially cause infinite recursion - but if we've got
// this far, we will have guaranteed a content ID, and as such we can safely update and not
// worry about it.
$this->updatepublishedfields($projectData,$fieldData);
}
return($contentID);
}
/**
* Publish a package stored on the URL passed to the content item linked with the project
* represented by the passed projectdata instance, and linked to a specific target
* @param array projectData An array of project data as returned by the H01_BUILDSERVICE::projectget function
* @param array fieldData An array of field data as returned by the H01_BUILDSERVICE::publishinggetfields function
* @param string packageurl The URL of the package you wish to add
* @param int target The target ID as found in the list of supported targets on the OCS server
* @return bool True on success, false on failure
*/
public function publishpackage($projectData,$fieldData,$packageurl,$target) {
$contentID=0;
if(is_array($this->data)) {
$contentID=$this->getcontentID($projectData,$fieldData);
} else {
// If this happens, you did something WRAUNG!
//echo('No data field found during publishing - wraung!');
return(false);
}
if($contentID==0) {
// This should never ever appen, but will happen if you attempted to create a project and the
// server failed for some reason...
//echo('No content ID created - this should never appen...');
return(false);
}
// Check the data for an association between this contentID and target combination
// The format of the data['contentlinks'] array:
// data['contentlinks'][projectID][target]=downloadpackageID
$projectID=$projectData['project']['projectid'];
$downloadpackageID=0;
if(array_key_exists($projectID,$this->data['downloadlinks'])) {
$tmpID=array_search($target,$this->data['downloadlinks'][$projectID]);
if($tmpID>0) {
// If so, send the package to that downloadpackage
$downloadpackageID=$tmpID;
} else if(count($this->data['downloadlinks'][$projectID])>11) {
// Are we full up? If so, bail out, panic!11eleventyone
// OCS only supports downloadpackageIDs of 1 through 12 (arbitrary limits, yay!)
// Also... 1-indexed? ;)
return(false);
} else {
// If not, send the package to the next available downloadpackage
$downloadpackageID=count($this->data['downloadlinks'][$projectID])+1;
$this->data['downloadlinks'][$projectID][$downloadpackageID]=$target;
$this->dataHasChanged=true;
}
} else {
// No data for this project at all - create array and give back the first downloadpackageID
$downloadpackageID=1;
$this->data['downloadlinks'][$projectID][1]=$target;
$this->dataHasChanged=true;
}
// Now that we finally have the downloadpackageID that we need to store the package to, do so!
$postdata=array(
'downloadtyp1'=>1,
'downloadname'.$downloadpackageID=>$target,
'downloadlink'.$downloadpackageID=>$packageurl,
'downloaddistributiontype'.$downloadpackageID=>$this->publisher['targets'][$target]['distribution'],
);
// Mmm, yummy hackery - this ensures that if the user has not entered any field data, we at
// least have /some/ data there.
$postdata['name']=$projectData['project']['name'];
$postdata['type']=1;
// Yeah, this is kiiinda nasty... hard coding these values squick me, but this /is/ OCS, and
// they're required, so... a bit of heuristics is alright.
$count=0;
foreach($fieldData['fields'] as $key => $field) {
if($field['name']=='Name' && $field['fieldtype']==H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_STRING) {
$postdata['name']=$field['data'];
if(++$count==2) {
break;
}
} else if($field['name']=='Type' && $field['fieldtype']==H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM) {
$postdata['type']=$this->fieldvaluesanitizer('Type',H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM,$field['data']);
if(++$count==2) {
break;
}
}
}
$didWeWin=$this->doPOST('content/edit/'.$contentID, $postdata);
return($didWeWin);
}
/**
* Look up the ID linked to a license by a certain name. If none is found, the ID 0 (equivalent
* to Other) is returned. In this case, you should also be setting te licensetext field.
*
* @param string licensename The name of the license you wish to get the ID for
* @return int The ID of the license, or 0 if it is "Other"
*/
public function licenseidbyname($licensename) {
$licensename=strtolower($licensename);
foreach($this->publisher['fields'] as $key => $field) {
if($field['name']=='License') {
$fieldOptions=$field['options'];
if(!is_array($fieldOptions)) {
$fieldOptions=$this->getitemlist($fieldOptions);
}
foreach($fieldOptions as $id => $value) {
if(strtolower($value)==$licensename) {
return($id);
}
}
}
}
return(0);
}
/**
* Update the fields on the OCS content item associated with a project - this will re-write
* all the fields found in the passed fieldData array, which are supported by the publisher,
* in other words you can't expect changes made through the web interface on any OCS server to
* stay there when using this service.
* @param array projectData An array of project data as returned by the H01_BUILDSERVICE::projectget function
* @param array fieldData An array of field data as returned by the H01_BUILDSERVICE::publishinggetfields function
* @return bool True on success, false on failure
*/
public function updatepublishedfields($projectData,$fieldData) {
$contentID=$this->getcontentID($projectData,$fieldData,false);
if($contentID==0) {
// We only update the field data if the content item actually exists!
return(false);
}
$postFields=array();
foreach($this->publisher['fields'] as $key => $publisherField) {
foreach($fieldData['fields'] as $key2 => $field) {
if($publisherField['name']==$field['name'] && $publisherField['fieldtype']==$field['fieldtype']) {
if($field['name']=='Enable Donation' && $field['data']=='No') {
$postFields[H01_BUILDSERVICE_OCS::fieldnametopostname($field['name'])]='';
} else {
$fieldvalue=$this->fieldvaluesanitizer($field['name'],$field['fieldtype'],$field['data']);
// Only add the field if it actually a correct value. Don't allow adding items which
// aren't valid (for example, an option value which does not exist in the list)
if($fieldvalue!==false) {
$postFields[H01_BUILDSERVICE_OCS::fieldnametopostname($field['name'])]=$fieldvalue;
}
}
break;
}
}
}
$this->doPOST('content/edit/'.$contentID, $postFields);
return(true);
}
/**
* Get a list of items. Only the functionname is required, and we take care of the heuristics of
* what the items consist of internally.
* @param functionName string A string name of a function on the remote server (such as 'content/categories')
* @return array An array of items in the form array( remote ID => human readable name)
*/
private $itemlistcache=array();
public function getitemlist($functionName) {
if(array_key_exists($functionName, $this->itemlistcache)) {
return($this->itemlistcache[$functionName]);
}
$list=array();
$contentdata=$this->doGET($functionName);
// We may get a false back from here, so...
if($contentdata) {
$hc=$this->curl_info['http_code'];
if($hc==100 || $hc>200 || $hc<299) {
// Load the resulting XML
$contentdata=simplexml_load_string($contentdata);
if((int)$contentdata->meta->statuscode != 100) {
// Error message should probably be set here...
echo("Error attempting to fetch items. Error returned by server was: \n{$contentdata->meta->message}");
return($list);
}
foreach($contentdata->data->children() as $item) {
// If you need any special nodes, this is where to build it
//if($functionName=='content/categories') {
//}
$list[(string)$item->id]=(string)$item->name;
}
}
}
$this->itemlistcache[$functionName]=$list;
return($list);
}
/**
* Translate the human-readable field name to the post variable name required for posting new data
* to the OCS server.
* @param string fieldname The human-readable name (from the array of fields)
* @return string The name used for the POST call
*/
private function fieldnametopostname($fieldname) {
$postname=str_replace(' ', '', strtolower($fieldname));
// This is only the special cases - a lot only need to be lower cased
switch($postname) {
case 'license':
$postname='licensetype';
break;
case 'licensetext':
$postname='license';
break;
case 'basedependency':
$postname='depend';
break;
case 'enabledonation':
$postname='donation';
break;
}
return($postname);
}
/**
* Make sure the value passed to the remote service is the right sort of one. For options,
* this means translating the named value into the key value required by the remote API
* @param fieldname string The name of the field in question
* @param fieldtype H01_BUILDSERVICE_PUBLISHER_FIELDTYPE The type of the field
* @param fieldvalue string The value of the field in question
* @return mixed The sanitized value (in the case of options, a non-existent value will cause a return of boolean false)
*/
private function fieldvaluesanitizer($fieldname,$fieldtype,$fieldvalue) {
foreach($this->publisher['fields'] as $key => $field) {
if($fieldname==$field['name'] && $fieldtype==$field['fieldtype']) {
if($fieldtype==H01_BUILDSERVICE_PUBLISHER_FIELDTYPE_ITEM) {
$fieldOptions=$field['options'];
if(!is_array($fieldOptions)) {
$fieldOptions=$this->getitemlist($fieldOptions);
}
foreach($fieldOptions as $optionKey => $optionName) {
if($optionName==$fieldvalue) {
return($optionKey);
}
}
// This is still some kind of value, but it is not a true value for an option index.
// This means we will get an error somewhere, but it'll be a correct error.
return(false);
}
}
}
return $fieldvalue;
}
/**
* This function should be called immediately before destruction of the instance of the class.
* It will tell you whether the data field for the user has changed, and whether it consequently
* should be saved back into the database.
* @return bool Whether or not the data has changed
*/
public function hasDataChanged() {
return $this->dataHasChanged;
}
}
?>