3
/* Copyright (C) 2000-2005 Thomas Bopp, Thorsten Hampel, Ludger Merkens
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* $Id: spm.in,v 1.13 2006/10/09 21:59:49 exodusd Exp $
22
constant cvs_version="$Id: spm.in,v 1.13 2006/10/09 21:59:49 exodusd Exp $";
24
//! steam package manager main script
25
//! Installs packages into the main server
26
//! Uploads files by coal and runs pike scripts for preinst and postinst
29
#include "../server/include/classes.h"
30
#include "../server/include/attributes.h"
32
string tmp_dir = "/tmp";
37
static object oInstall;
39
static int debug_output = 0;
42
object find_object(int id)
44
if ( objectp(oInstall) )
45
oInstall->find_object(id);
49
void list_packages( void|string name )
51
if ( stringp(name) && sizeof(name) < 1 ) name = UNDEFINED;
52
object conn = ((program)"connection.pike")();
53
conn->set_debug( debug_output );
55
conn->start( "steam.open-steam.org", 1900, "guest", "guest" );
57
object _filepath = conn->send_cmd( 0, "get_module", "filepath:tree" );
58
object _packages = conn->send_cmd( _filepath, "path_to_object",
59
"/home/admin/packages" );
60
array package_objs = conn->send_cmd( _packages, "get_inventory" );
61
mapping packages = ([ ]);
62
foreach ( package_objs, object pck ) {
63
string desc = conn->send_cmd( pck, "query_attribute", OBJ_DESC );
64
if ( !stringp(desc) ) desc = "";
65
packages[pck->get_identifier()] = desc;
68
werror("List of packages " + (stringp(name) ? "containing '"+name+"' " : "") + "on sTeam server:\n");
69
foreach( sort(indices(packages)), string package ) {
70
if ( stringp(name) && (search(package, name) < 0) ) continue;
71
werror(" " + package + " : \t" + (string)packages[package] + "\n");
75
int get_package(string pck_name, string filename)
77
object conn = ((program)"connection.pike")();
78
conn->set_debug( debug_output );
80
conn->start("steam.open-steam.org", 1900, "guest", "guest");
81
string content = conn->get_package(pck_name);
82
if ( !stringp(content) )
85
object f = Stdio.File(filename, "wct", 0600);
91
static string|int get_value(string val)
94
if ( sscanf(val, "%d", d) == 1 && (string)d == val )
99
void read_configs(string fname)
101
string configs = Stdio.read_file(fname);
102
mapping conf = ([ ]);
104
if ( !stringp(configs) )
105
error("failed to find config file at "+ fname);
106
array lines = configs / "\n";
107
foreach(lines, string line) {
108
if ( strlen(line) == 0 )
110
if ( line[0] == '#' ) // comment
115
if ( sscanf(line, "%s=%s", key, val) != 2 ) {
119
if ( sscanf(val, "hbs(%s)", v) > 0 ) {
120
conf[key] = get_value(v);
123
conf[key] = get_value(val);
128
/** Generate a random valid name for a new directory
129
* Returns the string of a valid directory name in the given directory and
130
* with the given prefix and suffix. The name will thus be
131
* dir+prefix+random+suffix.
132
* At the time of calling, no file with this name existed. The directory
133
* will be created and the path returned.
135
string make_tmp_dirname ( string dir, string prefix, string suffix ) {
136
if ( stringp(tmp_dir_name) && sizeof(tmp_dir_name)>0 )
138
string full_prefix = dir;
139
if ( ! has_suffix( full_prefix, "/" ) ) full_prefix += "/";
140
full_prefix += prefix;
141
string random_name = "";
145
random_name = full_prefix + replace(MIME.encode_base64(random_string(20),1) + suffix,"/","X");
146
} while ( Stdio.exist(random_name) );
147
if ( !Stdio.mkdirhier( random_name ) ) {
148
werror( "Could not create tmp directory: %s\n", random_name );
151
tmp_dir_name = random_name;
156
static void cleanup ()
158
// delete the temporary dir:
159
if ( stringp(tmp_dir_name) && sizeof(tmp_dir_name)>0 ) {
160
if ( Stdio.exist(tmp_dir_name) ) {
161
write( "Deleting temporary directory ...\n", tmp_dir_name );
162
if ( !Stdio.recursive_rm( tmp_dir_name ) )
163
werror( "Could not delete temporary directory: %s\n", tmp_dir_name );
166
//if ( search(pck_name,tmp_dir) == 0 )
167
// Filesystem.System()->rm( pck_name );
170
int check_spm(string pname, object spmModule, object connection, void|int force)
172
object tfs = Filesystem.Tar(pname);
173
if ( !objectp(tfs) ) {
174
werror(pname + " not a valid SPM !\n");
177
mixed xml = tfs->open("package.xml", "r");
178
string packageXML = xml->read();
180
mapping config =spmModule->spm_check_configuration(packageXML);
181
mapping pmod = connection->send_cmd(0, "get_module", config->name);
182
if ( !objectp(pmod) )
183
pmod = connection->send_cmd(0, "get_module", "package:"+config->name);
184
if ( objectp(pmod) ) {
185
if ( spmModule->spm_version_value(config->version) <= spmModule->spm_version_value(pmod->get_version()) ) {
187
write("Found installed module with version %O, forcing installation anyway.\n", pmod->get_version());
190
werror("Found installed module with version %O, skipping installation !\n", pmod->get_version());
195
werror("Found installed module - updating to %O (previous version %O)\n",
196
config->version, pmod->get_version());
203
//! Call Script with package to install, for example
205
//! spm is a packed archive with the following directories:
206
//! sources/ - files to upload on the server with the present structure
207
//! xml/ - xml code to set attributes, access and so on in server files
208
//! steam/ - meta information of the package and installation perequesites
210
int main(int argc, array(string) argv)
212
string server_path = "@steamcore@";
213
string config_path = "@configdir@";
215
if ( config_path == "" )
216
config_path = server_path + "/config";
218
if ( search(argv, "--help") >= 0 ) {
219
write("SPM: sTeam package manager.\n"+
220
"This utility connects to a running local sTeam server and\n"+
221
"installs new packages. Usage is spm <options>:\n"+
222
" -i --install <package-name>: Installs ar updates a package.\n"+
223
" The package is either retrieved from the main sTeam server\n"+
224
" or located on the local disk (package-name can be a path name).\n"+
225
" -o --old-install <package-name>: Installs or updates a package\n"+
226
" using the old installation mechanism. This is deprecated and\n"+
227
" you should only use this method when instructed to.\n"+
228
" -f --force : Forces installation of a package, even if the\n"+
229
" package is already installed with that version.\n"+
230
" -l --list [name] : Lists all packages available for installation\n"+
231
" on the main sTeam server (www.open-steam.org). If an argument\n"+
232
" is given, only packages which contain that text are listed.\n"+
233
" -d --dest <directory> : Install the package to the destination"+
235
" -s --server <hostname> : Install on a given server.\n"+
236
" -p --port <port> : use another port for installation\n"+
237
" (default is 1900).\n"+
238
" -c --configure <package-name> : Just configure a package\n"+
239
" (if already installed).\n");
245
// get all command line options:
246
array tmp_options = Getopt.find_all_options( argv, ({
247
({ "install", Getopt.HAS_ARG, ({ "-i", "--install" }) }),
248
({ "old-install", Getopt.HAS_ARG, ({ "-o", "--old-install" }) }),
249
({ "list", Getopt.MAY_HAVE_ARG, ({ "-l", "--list" }), ({ }), "" }),
250
({ "dest", Getopt.HAS_ARG, ({ "-d", "--dest" }) }),
251
({ "configure", Getopt.HAS_ARG, ({ "-c", "--configure" }) }),
252
({ "server", Getopt.HAS_ARG, ({ "-s", "--server" }) }),
253
({ "port", Getopt.HAS_ARG, ({ "-p", "--port" }) }),
254
({ "debug", Getopt.NO_ARG, ({ "--debug" }) }),
255
({ "force", Getopt.NO_ARG, ({ "-f", "--force" }) }),
257
// make a mapping out of the options:
258
mapping options = ([ ]);
259
foreach ( tmp_options, array option ) options[ option[0] ] = option[1];
260
if ( options["debug"] ) debug_output = 1;
261
if ( options["force"] ) force = 1;
263
master()->add_include_path(server_path+"/server/include");
264
master()->add_program_path(server_path+"/server/");
265
master()->add_program_path(server_path+"/spm/");
266
master()->add_module_path(server_path+"/server/libraries");
267
master()->add_program_path(server_path+"/server/net/coal");
268
add_constant("find_object", find_object);
269
read_configs(config_path+"/steam.cfg");
271
if ( options["list"] ) {
272
list_packages( options["list"] );
276
pck_name = options["install"];
277
if ( !stringp(pck_name) ) pck_name = options["old-install"];
278
if ( !stringp(pck_name) ) pck_name = options["configure"];
280
if ( !stringp(pck_name) ) {
281
werror("Missing filename or URL for installation / configuration...\n");
284
string spm_filename = basename( pck_name );
285
sscanf( spm_filename, "%s.gz", spm_filename );
288
mkdir(dirname(tmp_dir));
290
if ( sscanf(pck_name, "http://%s", url) > 0 ) {
291
// the temporary file for download...
293
mapping headers = ([ ]);
295
if ( sscanf(url, "%s:%s@%s", user, pass, url) == 3 ) {
296
write("User: "+ user + "\n");
297
headers = ([ "authorization": "Basic " +
298
MIME.encode_base64(user+":"+pass), ]);
300
write("Connecting to http://" + url+"\n");
301
object query = Protocols.HTTP.get_url("http://"+url, ([ ]), headers);
302
mapping d = query->cast("mapping");
303
//werror("RESULT=\n"+sprintf("%O\n",indices(d)));
304
string data = d->data;
306
sscanf(url, "%*s/%s", fname);
307
write("Transfered " + strlen(data) + " bytes...\n");
308
tmp_dir_name = make_tmp_dirname(tmp_dir,"spm_","");
309
pck_name = tmp_dir_name + "/" + fname;
310
object f = Stdio.File(pck_name, "wct",0600);
314
write("Package received...\n");
317
if ( !Stdio.exist(pck_name) ) {
318
write("Getting file from package server...\n");
319
tmp_dir_name = make_tmp_dirname(tmp_dir,"spm_","");
320
string tmp_filename = tmp_dir_name + "/" + pck_name;
321
if ( !get_package(pck_name, tmp_filename) ) {
322
werror("Package not found on server ... Try -l to list packages.\n");
325
pck_name = tmp_filename;
327
master()->add_program_path("../spm");
329
if ( sscanf(pck_name, "%s.gz", pck_name) >= 1 ) {
330
write("Unzipping...\n");
331
string destname = pck_name;
332
if ( search(destname,tmp_dir) != 0 ) {
333
tmp_dir_name = make_tmp_dirname(tmp_dir,"spm_","");
334
destname = tmp_dir_name + "/" + destname;
336
object f = Stdio.File(destname, "wct");
337
int ret = Process.create_process( ({ "gunzip", "-c", "-f",
338
pck_name+".gz" }), ([ "stdout" : f ]))->wait();
340
if ( search(pck_name,tmp_dir) == 0 )
341
Filesystem.System()->rm( pck_name+".gz" );
345
write("Opening spm archive ...");
346
object fsystem = Filesystem.Tar(pck_name);
349
// check for package.xml
350
if ( !objectp(fsystem) ) {
351
werror("Not a valid spm package (not a tar archive): %s\n", spm_filename);
354
if ( options["install"] && search( fsystem->get_dir(), "/package.xml" )<0 ) {
355
werror("The package %s is deprecated (it doesn't contain a /package.xml"
356
+" file).\nYou need to install it with the -o or --old-install "
357
+"command instead:\n spm -o %s\n", spm_filename, spm_filename);
360
if ( options["old-install"]
361
&& search( fsystem->get_dir(), "/package.xml" ) >= 0 ) {
362
werror("The package %s is not deprecated (it contains a /package.xml"
363
+" file).\nYou need to install it with the -i or --install "
364
+"command instead:\n spm -i %s\n", spm_filename, spm_filename);
369
string server = options["server"];
370
int port = (int)(vars["port"]);
371
if ( stringp(server) ) port = 1900;
372
else if ( stringp(vars["ip"]) && sizeof(vars["ip"]) )
375
server = "localhost";
376
if ( stringp(options["port"]) )
377
sscanf( options["port"], "%d", port );
379
write("Connecting sTeam on "+server+":"+port+"\n");
380
object conn = ((program)"connection.pike")();
381
conn->set_debug( debug_output );
382
string pw = read_password("Root Password for server", "steam");
385
if ( sscanf(pck_name, "%s.spm", pname) != 1 ) {
389
vars["package"] = (pname / "/")[-1];
390
vars["fs"] = pname+".spm";
391
if ( !stringp(options["dest"]) )
394
vars["dest"] = options["dest"];
396
conn->set_fsystem(fsystem, vars);
397
conn->start(server, port, "root", pw);
398
if ( options->configure ) {
399
//TODO: this is hardcoded to configure only the web package!?
400
conn->configure_web();
401
werror("Configuration of package completed !");
405
// connect to the server and register the new package module
406
if ( options["old-install"] ) {
407
conn->upload_package(vars);
408
werror("\nInstallation successfull ("+conn->iInstall + " new Files, "+
409
conn->iUpdate + " updated).\n\n");
411
} else if ( options["install"] ) {
412
object package_file = Stdio.File( pck_name, "r" );
413
object _filepath = conn->send_cmd( 0, "get_module", "filepath:tree" );
414
if ( !objectp(_filepath) ) {
415
werror( "Unable to find filepath module on server!\n" );
418
object _spm = conn->send_cmd( 0, "get_module", "SPM" );
419
if ( !objectp(_spm) ) {
420
werror( "Unable to find spm module on server!\n" );
423
object dir = conn->send_cmd( _filepath, "path_to_object", "/packages" );
424
object root_dir = conn->send_cmd( _filepath, "path_to_object", "/" );
425
if ( !objectp(dir) || !objectp(root_dir) ) {
426
werror( "Unable to find package or root directory on server!" );
429
if ( !check_spm(pck_name, _spm, conn, force) )
431
object new_obj = conn->send_cmd( dir, "get_object_byname", spm_filename );
432
if ( !objectp(new_obj) ) {
433
object _docfactory = conn->send_cmd( 0, "get_factory", CLASS_DOCUMENT );
434
if ( !objectp(_docfactory) ) {
435
werror( "Unable to find document factory on server!\n" );
438
new_obj = conn->send_cmd( _docfactory, "execute", ([ "name": spm_filename, ]) );
439
if ( !objectp(new_obj) ) {
440
werror( "Could not create temporary package file on server!\n" );
443
conn->send_cmd( new_obj, "move", dir );
445
conn->send_cmd( new_obj, "set_content", package_file->read() );
446
package_file->close();
447
write( "Uploaded package %s ...\n", spm_filename );
449
conn->send_cmd( _spm, "install_spm", ({ new_obj, root_dir }) );
450
write( "Installed package %s ...\n", spm_filename );
451
// delete temporary package on server
452
conn->send_cmd( new_obj, "delete" );
453
write( "Deleted temporary package file on server\n" );