Repository URL to install this package:
|
Version:
18.5.0-1 ▾
|
#!/usr/bin/perl
# (c) Copyright 2006-2013. CodeWeavers, Inc.
use warnings;
use strict;
# Portable which(1) implementation
sub cxwhich($$;$)
{
my ($dirs, $app, $noexec)=@_;
if ($app =~ /^\//)
{
return $app if ((-x $app or $noexec) and -f $app);
}
elsif ($app =~ /\//)
{
require Cwd;
my $path=Cwd::cwd() . "/$app";
return $path if ((-x $path or $noexec) and -f $path);
}
else
{
foreach my $dir (split /:/, $dirs)
{
return "$dir/$app" if ($dir ne "" and (-x "$dir/$app" or $noexec) and -f "$dir/$app");
}
}
return undef;
}
# Fast dirname() implementation
sub _cxdirname($)
{
my ($path)=@_;
return undef if (!defined $path);
return "." if ($path !~ s!/+[^/]+/*$!!s);
return "/" if ($path eq "");
return $path;
}
# Locate where CrossOver is installed by looking for the directory
# where the cxmenu script is located, unwinding symlinks on the way
sub locate_cx_root(;$)
{
my ($fallback)=@_;
my $argv0=cxwhich($ENV{PATH},$0);
$argv0=$0 if (!defined $argv0);
if ($argv0 !~ m+^/+)
{
require Cwd;
$argv0=Cwd::cwd() . "/$argv0";
}
my $dir=_cxdirname($argv0);
my $bindir=$dir;
$bindir =~ s%/lib$%/bin%;
while (!-x "$bindir/cxmenu" or !-f "$bindir/cxmenu")
{
last if (!-l $argv0);
$argv0=readlink($argv0);
$argv0="$dir/$argv0" if ($argv0 !~ m+^/+);
$dir=_cxdirname($argv0);
$bindir=$dir;
$bindir =~ s%/lib$%/bin%;
}
$bindir =~ s%/(?:\./)+%/%g;
$bindir =~ s%/\.$%%;
$ENV{CX_ROOT}=_cxdirname($bindir);
if ((!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu") and
$fallback)
{
$ENV{CX_ROOT}=$fallback;
}
if (!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu")
{
my $name0=$0;
$name0 =~ s+^.*/++;
print STDERR "$name0:error: could not find CrossOver in '$ENV{CX_ROOT}'\n";
exit 1;
}
return $ENV{CX_ROOT};
}
BEGIN {
unshift @INC, locate_cx_root() . "/lib/perl";
}
use CXLog;
use CXUtils;
{
package CXLinuxDebian;
use CXDebian;
use base "CXDebian";
sub new($$$$$)
{
my ($class, $deb_package, $productid, $buildroot, $installroot)=@_;
my $self=CXDebian::new($class, $buildroot);
if ($self)
{
$self->{deb_package}=$deb_package;
$self->{conf_filter}=join("|", $productid, CXUtils::get_product_id(), CXUtils::get_builtin_product_id());
$self->{installroot}=$installroot;
$self->{docdir}="/usr/share/doc/$deb_package";
}
return $self;
}
sub map_directory($$$)
{
my ($self, $root, $dir)=@_;
if ($self->{doc})
{
return "$self->{docdir}/$dir";
}
return undef if ($dir eq ".mojosetup"); # MojoSetup
return "" if ($dir eq "bin");
return "" if ($dir eq "doc"); # Non-Debian doc directory
return "$self->{docdir}/$dir" if ($dir =~ s!^doc/!!);
return "" if ($dir eq "etc");
return "" if ($dir eq "lib" or $dir eq "lib/python");
return undef if ($dir eq "support");
return "$self->{installroot}/$dir";
}
sub map_file($$$)
{
my ($self, $root, $file)=@_;
if ($self->{doc})
{
return undef if ($file eq "changelog.Debian.gz");
return undef if ($file eq "copyright");
return "$self->{docdir}/$file";
}
return undef if ($file eq ".uninstall"); # MojoSetup
if ($file =~ m!^bin/[^/]+$! and -l "$root/$file")
{
# Don't package cxmenu's shortcut files
my $dst=readlink "$root/$file";
return undef if ($dst =~ m%/desktopdata/cxmenu/Shortcuts/%);
}
return undef if ($file =~ m%^etc/(?:$self->{conf_filter})\.conf%);
return undef if ($file =~ m%^lib/python/.*\.pyc$%);
return undef if ($file eq "doc"); # Debian's doc symlink
return "$self->{docdir}/$file" if ($file =~ s!^doc/!!);
return "$self->{docdir}/changelog" if ($file eq "changelog.txt");
return "$self->{docdir}/changelog.html" if ($file eq "changelog.html");
return "$self->{docdir}/license.txt" if ($file eq "license.txt");
return "$self->{docdir}/README" if ($file eq "README");
return "$self->{installroot}/$file";
}
}
{
package CXLinuxRPM;
use CXRPM;
use base "CXRPM";
sub new($$)
{
my ($class, $productid)=@_;
my $self=$class->SUPER::new();
$self->{conf_filter}=join("|", $productid, CXUtils::get_product_id(), CXUtils::get_builtin_product_id());
return $self;
}
sub map_directory($$$$)
{
my ($self, $root, $dir, $mode)=@_;
if ($self->{doc})
{
push @{$self->{dirs}}, "doc/$dir";
return ("doc/$dir", $mode);
}
return undef if ($dir eq ".mojosetup"); # MojoSetup
return undef if ($dir eq "support");
push @{$self->{dirs}}, $dir;
return ($dir, $mode);
}
sub map_file($$$$)
{
my ($self, $root, $file, $mode)=@_;
if ($self->{doc})
{
# Debian specific
return undef if ($file =~ /^(?:changelog\.Debian(?:\.gz)?|copyright)$/);
if ($file =~ /^changelog(\.gz)?$/)
{
push @{$self->{docfiles}}, "changelog.txt";
return ("changelog.txt.gz", $mode, 1) if (defined $1);
return ("changelog.txt", $mode);
}
if ($file =~ /^changelog\.html(\.gz)?$/)
{
push @{$self->{docfiles}}, "changelog.html";
return ("changelog.html.gz", $mode, 1) if (defined $1);
return ("changelog.html", $mode);
}
if ($file =~ /^README(\.gz)?$/)
{
push @{$self->{docfiles}}, "README";
return ($file, $mode, defined $1);
}
if ($file =~ /^license\.txt(\.gz)?$/)
{
push @{$self->{files}}, "license.txt";
return ($file, $mode, defined $1);
}
push @{$self->{files}}, "doc/$file";
return ("doc/$file", $mode);
}
# MojoSetup
return undef if ($file eq ".uninstall");
# Debian's doc link
return undef if ($file eq "doc" and -l "$root/$file");
return undef if ($file =~ m%^etc/(?:$self->{conf_filter})\.conf%);
if ($file =~ m!^bin/[^/]+$! and -l "$root/$file")
{
# Don't package cxmenu's shortcut files
my $dst=readlink "$root/$file";
return undef if ($dst =~ m%/desktopdata/cxmenu/Shortcuts/%);
}
elsif ($file =~ m%^(?:README|changelog\.txt|changelog\.html)$%)
{
push @{$self->{docfiles}}, $file;
return ($file, $mode);
}
push @{$self->{files}}, $file;
return ($file, $mode);
}
}
{
package CXRSunpkg;
use CXSunpkg;
use base "CXSunpkg";
sub new($$$$)
{
my ($class, $pkgdir, $productid, $compress)=@_;
my $self=$class->SUPER::new($pkgdir, $compress);
$self->{conf_filter}=join("|", $productid, CXUtils::get_product_id(), CXUtils::get_builtin_product_id()) if ($self);
return $self;
}
sub package_directory($$$$)
{
my ($self, $root, $dir, $mode)=@_;
# Note: No need to handle Debian's special documentation directory here
return undef if ($dir eq ".mojosetup"); # MojoSetup
return undef if ($dir eq "support");
return $mode;
}
sub package_file($$$$)
{
my ($self, $root, $file, $mode)=@_;
# Note: No need to handle Debian's special documentation directory here
return undef if ($file eq ".uninstall"); # MojoSetup
return undef if ($file =~ m%^etc/(?:$self->{conf_filter})\.conf%);
if ($file =~ m!^bin/[^/]+$! and -l "$root/$file")
{
# Don't package cxmenu's shortcut files
my $dst=readlink "$root/$file";
return undef if ($dst =~ m%/desktopdata/cxmenu/Shortcuts/%);
}
return $mode;
}
}
sub create_tmpdir()
{
my $tmpdir;
if (-w $ENV{CX_ROOT})
{
$tmpdir="$ENV{CX_ROOT}/support/desktopdata";
if ($> == 0)
{
# Make sure desktopdata is created with the proper permissions
my $umask=umask 0022;
my $rc=!cxmkpath($tmpdir);
umask $umask;
if ($rc)
{
cxerr("unable to create the '$tmpdir' directory: $@\n");
return undef;
}
}
}
else
{
require CXBottle;
$tmpdir=CXBottle::get_user_dir() . "/desktopdata";
}
return "$tmpdir/cxrepackage-$$";
}
sub move_package($$$$)
{
my ($dir, $pattern, $label, $name)=@_;
my @files=CXUtils::cxglob($dir, $pattern);
if (!@files)
{
cxerr("unable to find the $name package\n");
return 0;
}
if (@files > 1)
{
cxerr("found more than one $name package: @files\n");
return 0;
}
my $filename=cxbasename($files[0]);
if (!defined cxmv($files[0], $filename))
{
cxerr("unable to move '$files[0]' to the current directory: $!\n");
return 0;
}
rmdir cxdirname($files[0]);
print "$label: $filename\n";
return 1;
}
# Process command-line options
my $opt_release;
my $opt_deb;
my $opt_deb32;
my $opt_deb64;
my $opt_rpm;
my $opt_sunpkg;
my $opt_sunzip;
my $opt_productid;
my $opt_verbose;
my $opt_help;
require CXOpts;
my $cxopts=CXOpts->new();
$cxopts->add_options(["release=s" => \$opt_release,
"deb" => \$opt_deb,
"deb32" => \$opt_deb32,
"deb64" => \$opt_deb64,
"rpm" => \$opt_rpm,
"sunpkg" => \$opt_sunpkg,
"sunzip=s" => \$opt_sunzip,
"productid=s" => \$opt_productid,
"verbose!" => \$opt_verbose,
"?|h|help" => \$opt_help
]);
my $err=$cxopts->parse();
CXLog::fdopen(2) if ($opt_verbose);
# Validate the command line options
my $usage;
if ($err)
{
cxerr("$err\n");
$usage=2;
}
elsif ($opt_help)
{
$usage=0;
}
else
{
if (!defined $opt_release)
{
cxerr("you must specify the --release option\n");
$usage=2;
}
if (!$opt_deb and !$opt_deb32 and !$opt_deb64 and !$opt_rpm and !$opt_sunpkg)
{
cxerr("you must specify the package format using --deb, --deb32, --deb64, --rpm or --sunpkg\n");
$usage=2;
}
if (defined $opt_sunzip)
{
if (!$opt_sunpkg)
{
cxerr("--sunzip can only be used with --sunpkg\n");
$usage=2;
}
if (defined $opt_sunzip)
{
require CXSunpkg;
if (!CXSunpkg::is_valid_zip_format($opt_sunzip))
{
cxerr("unknown compression format '$opt_sunzip' for the --sunzip option\n");
$usage=2;
}
}
}
$opt_sunzip||="bzip2";
if (defined $opt_productid)
{
$err=CXUtils::check_product_id($opt_productid);
if (defined $err)
{
cxerr("$err\n");
$usage=1;
}
}
else
{
$opt_productid=CXUtils::get_product_id();
}
}
# Print usage
if (defined $usage)
{
my $name0=cxname0();
if ($usage)
{
cxerr("try '$name0 --help' for more information\n");
exit $usage;
}
print "Usage: $name0 --release RELEASE [--deb] [--deb32] [--deb64] [--rpm] [--sunpkg]\n";
print " [--sunzip FMT] [--productid ID] [--verbose] [--help]\n";
print "\n";
print "Builds a Debian or RPM package from the current CrossOver installation.\n";
print "\n";
print "Options:\n";
print " --release RELEASE Specifies the package's release number\n";
print " --deb Generates a 32-bit multiarch Debian package\n";
print " --deb32 Generates a 32-bit Debian package\n";
print " --deb64 Generates a 64-bit Debian package\n";
print " --rpm Generates an RPM package\n";
print " --sunpkg Generates a Sun package\n";
print " --sunzip FMT The compression format to use. The default is bzip2, the\n";
print " others are none, gzip and 7z\n";
print " --help, -h Shows this help message\n";
print "\n";
print "Advanced options:\n";
print " --productid ID Use ID as the package's product id\n";
print " The product id is what differentiates CrossOver packages\n";
print " from each other in side-by-side installations\n";
print " --verbose Output more information about what is going on\n";
exit 0;
}
my $rc;
if ($opt_deb or $opt_deb32 or $opt_deb64)
{
my @types;
push @types, "march" if ($opt_deb);
push @types, "i386" if ($opt_deb32);
push @types, "amd64" if ($opt_deb64);
foreach my $type (@types)
{
# Use a pseudo-loop to simplify error handling
my ($tmpdir, $lrc);
error: while (1)
{
my $template="$ENV{CX_ROOT}/share/crossover/cxrepackage/deb.";
if (!-f "${template}build")
{
cxerr("the --deb/--deb32/--deb64 options are not supported on this platform\n");
$lrc=1;
last error;
}
$tmpdir=create_tmpdir();
if (!defined $tmpdir)
{
$lrc=1;
last error;
}
my $deb_package=($opt_productid eq CXUtils::get_builtin_product_id() ?
"crossover" :
$opt_productid);
$deb_package="$deb_package-legacy" if ($type ne "march");
$deb_package="ia32-$deb_package" if ($type eq "amd64");
my $installroot="/opt/$opt_productid";
my $cxdebian=CXLinuxDebian->new($deb_package, $opt_productid, $tmpdir, $installroot);
if (!$cxdebian)
{
$lrc=1;
last error;
}
# Register the files to install
if (!$cxdebian->add_tree($ENV{CX_ROOT}))
{
$lrc=1;
last error;
}
my $docdir=readlink("$ENV{CX_ROOT}/doc");
if (defined $docdir and -d $docdir)
{
$cxdebian->{doc}=1;
if (!$cxdebian->add_tree($docdir))
{
$lrc=1;
last error;
}
}
# Generate the Debian control files
my ($arch, $csa, $cma)=($type eq "march") ? ("i386", "#", "") : ($type, "", "#");
my $cwma=($type eq "i386") ? "#" : "";
my $today=CXUtils::rfc822time(time);
foreach my $file ("debian/build",
"debian/changelog",
"debian/compat",
"debian/control",
"debian/copyright",
"debian/doc-base",
"debian/lintian-overrides",
"debian/postinst",
"debian/postrm",
"debian/preinst",
"debian/prerm",
"debian/rules")
{
my $src="$template" . cxbasename($file);
$lrc=CXUtils::generate_from_template("$tmpdir/$file", $src,
{arch => $arch,
csa => $csa,
cma => $cma,
cwma => $cwma,
deb_package => $deb_package,
product_id => $opt_productid,
release => $opt_release,
date => $today
});
last error if ($lrc);
}
# Finally, generate the Debian package
$lrc=$cxdebian->build($arch);
last error if ($lrc);
# Move the Debian package to the current directory
my ($label, $bits)=($type eq "march") ? ("deb", "32") :
($arch eq "i386") ? ("deb32", "32") :
("deb64", "64") ;
$lrc=1 if (!move_package($tmpdir, "*.deb", $label, "${bits}bit Debian"));
last;
}
if (defined $tmpdir)
{
require File::Path;
File::Path::rmtree($tmpdir);
}
$rc=1 if ($lrc);
}
}
if ($opt_rpm)
{
# Use a pseudo-loop to simplify error handling
my ($tmpdir, $lrc);
error: while (1)
{
my $template="$ENV{CX_ROOT}/share/crossover/cxrepackage/rpm.spec";
if (!-f $template)
{
cxerr("the --rpm option is not supported on this platform\n");
$lrc=1;
last error;
}
my $cxlinuxrpm=CXLinuxRPM->new($opt_productid);
if (!defined $cxlinuxrpm->{rpmbuild})
{
$lrc=1;
last error;
}
# Copy $CX_ROOT so it has the expected directory structure
$tmpdir=create_tmpdir();
if (!defined $tmpdir)
{
$lrc=1;
last error;
}
my $imagedir="$tmpdir/image";
if (!$cxlinuxrpm->create_image($ENV{CX_ROOT}, "$imagedir/opt/$opt_productid"))
{
$lrc=1;
last error;
}
my $docdir=readlink("$ENV{CX_ROOT}/doc");
if (defined $docdir and -d $docdir)
{
if (!cxmkpath("$imagedir/opt/$opt_productid/doc", 0700))
{
cxerr("unable to create the '$imagedir/opt/$opt_productid/doc' directory: $@\n");
$lrc=1;
last error;
}
my $mode=(stat($docdir))[2] & 07777;
chmod($mode, "$imagedir/opt/$opt_productid/doc");
$cxlinuxrpm->{doc}=1;
if (!$cxlinuxrpm->create_image($docdir, "$imagedir/opt/$opt_productid"))
{
$lrc=1;
last error;
}
}
# Generate the spec file
my $rpm_package=($opt_productid eq CXUtils::get_builtin_product_id() ?
"crossover" :
$opt_productid);
require CXRPM;
my $dir_list=join("\n", map { "\%dir " . CXRPM::escape_file_path("/opt/$opt_productid/$_") } sort @{$cxlinuxrpm->{dirs}});
my $file_list=join("\n", (map { "%doc " . CXRPM::escape_file_path("/opt/$opt_productid/$_") } sort @{$cxlinuxrpm->{docfiles}}), (map { CXRPM::escape_file_path("/opt/$opt_productid/$_") } sort @{$cxlinuxrpm->{files}}));
my $specfile="$tmpdir/rpm.spec";
$lrc=CXUtils::generate_from_template($specfile, $template,
{rpm_package => $rpm_package,
product_id => $opt_productid,
release => $opt_release,
buildroot => $imagedir,
cx_root => "/opt/$opt_productid",
dir_list => $dir_list,
file_list => $file_list
});
last error if ($lrc);
# Finally, generate the RPM package
$lrc=$cxlinuxrpm->build($tmpdir, "i386");
last error if ($lrc);
# Move the rpm package to the current directory
$lrc=1 if (!move_package($tmpdir, "i?86/*.rpm", "rpm", "RPM"));
last;
}
if (defined $tmpdir)
{
require File::Path;
File::Path::rmtree($tmpdir);
}
$rc=1 if ($lrc);
}
if ($opt_sunpkg)
{
# Use a pseudo-loop to simplify error handling
my ($pkgdir, $lrc);
error: while (1)
{
my $template="$ENV{CX_ROOT}/share/crossover/cxrepackage/sunpkg.";
if (!-f "${template}pkginfo")
{
cxerr("the --sunpkg option is not supported on this platform\n");
$lrc=1;
last error;
}
require CXSunpkg;
my $sun_package=($opt_productid eq CXUtils::get_builtin_product_id() ?
"cxoffice" :
$opt_productid);
$sun_package=CXSunpkg::compute_package_name("", $sun_package);
cxlog("Creating solaris tree for $sun_package\n");
$pkgdir="$sun_package";
$pkgdir="sunpkg/$pkgdir" if ($pkgdir eq $ENV{CX_ROOT});
if (-d $pkgdir)
{
require File::Path;
if (!File::Path::rmtree($pkgdir))
{
cxerr("unable to delete the '$pkgdir' directory\n");
$lrc=1;
last error;
}
}
my $cxrsunpkg=CXRSunpkg->new($pkgdir, $opt_productid, $opt_sunzip);
last if (!$cxrsunpkg);
my ($mday, $mon, $year)=(localtime(time))[3,4,5];
$mon++;
$year+=1900;
my $today=sprintf("%d/%02d/%02d", $year, $mon, $mday);
if (!$cxrsunpkg->generate_install_files($template,
["pkginfo",
"install/checkinstall",
"install/compver",
"install/copyright",
"install/depend",
"install/postinstall",
"install/preremove"],
{sun_package => $sun_package,
product_id => $opt_productid,
release => $opt_release,
date => $today,
noverify => ($opt_sunzip eq "none" ? "" : "none")
}))
{
$lrc=1;
last error;
}
# Note: No need to handle Debian's special documentation directory here
if (!$cxrsunpkg->add_tree("reloc/\$PKGINST", $ENV{CX_ROOT}, 0755) or
!$cxrsunpkg->finalize("\$PKGINST"))
{
$lrc=1;
last error;
}
print "sunpkg: $pkgdir\n";
last;
}
if ($lrc and defined $pkgdir)
{
require File::Path;
File::Path::rmtree($pkgdir);
}
$rc=1 if ($lrc);
}
exit($rc || 0);