Warning, /sdk/kdesrc-build/kdesrc-build-setup is written in an unsupported language. File is not indexed.

0001 #!/usr/bin/env perl
0002 
0003 # Script to create a configuration file for kdesrc-build.
0004 #
0005 # Copyright © 2011, 2020-2022 Michael Pyne. <mpyne@kde.org>
0006 # Home page: https://apps.kde.org/kdesrc_build/
0007 #
0008 # This program is free software; you can redistribute it and/or modify it under
0009 # the terms of the GNU General Public License as published by the Free Software
0010 # Foundation; either version 2 of the License, or (at your option) any later
0011 # version.
0012 #
0013 # This program is distributed in the hope that it will be useful, but WITHOUT
0014 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0015 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
0016 # details.
0017 #
0018 # You should have received a copy of the GNU General Public License along with
0019 # this program; if not, write to the Free Software Foundation, Inc., 51
0020 # Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0021 
0022 use v5.28;
0023 use strict;
0024 use warnings;
0025 
0026 # On many container-based distros, even FindBin is missing to conserve space.
0027 # But we can use File::Spec to do nearly the same.
0028 my $RealBin;
0029 my $modPath;
0030 
0031 # The File::Spec calls have to run when parsing (i.e. in BEGIN) to make the
0032 # 'use lib' below work (which itself implicitly uses BEGIN { })
0033 BEGIN {
0034     use File::Spec;
0035 
0036     # resolve symlinks
0037     my $scriptPath = $0;
0038     for (1..16) {
0039         last unless -l $scriptPath;
0040         $scriptPath = readlink $scriptPath;
0041     }
0042     die "Too many symlinks followed looking for script" if -l $scriptPath;
0043 
0044     my ($volume, $directories, $script) = File::Spec->splitpath($scriptPath);
0045 
0046     $RealBin = File::Spec->catpath($volume, $directories, '');
0047     die "Couldn't find base directory!" unless $RealBin;
0048 
0049     # Use modules in git repo if running from git dir, otherwise assume
0050     # system install
0051     $modPath = File::Spec->rel2abs('modules', $RealBin);
0052     $modPath = ($RealBin =~ s,/bin/?$,/share/kdesrc-build/modules,r)
0053         unless -d $modPath;
0054 
0055     die "Couldn't find modules for kdesrc-build-setup!" unless $modPath;
0056 }
0057 
0058 use lib "$modPath"; # Make ksb:: modules available
0059 
0060 use ksb;
0061 use ksb::FirstRun;
0062 
0063 use Cwd qw(abs_path);
0064 use File::Basename;
0065 use File::Copy;
0066 use File::Path qw(make_path);
0067 use File::Temp qw(tempfile);
0068 use IO::Pipe;
0069 use List::Util qw(max min first);
0070 
0071 our $VERSION = 0.10; # Not user-visible yet.
0072 
0073 my $OS = `uname`; # Check whether we're using Linux or FreeBSD
0074 
0075 sub clearScreen
0076 {
0077     require POSIX;
0078     my $termios = POSIX::Termios->new();
0079     $termios->getattr(1); # Get STDOUT attributes
0080 
0081     require Term::Cap;
0082     my $terminal = Term::Cap->Tgetent({OSPEED => $termios->getospeed});
0083 
0084     # Force the clear characters to be output immediately.
0085     # Otherwise it might overlap with other output, like error messages.
0086     local $| = 1;
0087 
0088     print $terminal->Tputs('cl', 0);
0089 
0090     return 0;
0091 }
0092 
0093 sub runDialogExecutable (@args)
0094 {
0095     # Allow for 3 more file descriptors (on top of the normally allowed 0, 1,
0096     # 2) to survive the upcoming exec
0097     # See "SYSTEM_FD_MAX" in perldoc:perlvar
0098     $^F = 5;
0099 
0100     my $pipe = new IO::Pipe;
0101     my $pid;
0102 
0103     if ($pid = fork()) {
0104         # Parent
0105         $pipe->reader();
0106 
0107         my $output = <$pipe>;
0108 
0109         waitpid $pid, 0;
0110         my $result = ($? >> 8);
0111         $pipe->close();
0112 
0113         # dialog uses -1 as an exit code, Perl gets just the standard 8 bits
0114         # the rest of UNIX uses...
0115         if ($? == -1) {
0116             clearScreen();
0117             die "Failed to run dialog(1): $@";
0118         }
0119         elsif ($result == 255) {
0120             clearScreen();
0121             die "Canceled the dialog";
0122         }
0123         return $output || $result;
0124     }
0125     elsif (defined $pid) {
0126         # Child
0127         $pipe->writer();
0128         my $outputFd = $pipe->fileno();
0129 
0130         print "Using fd $outputFd";
0131         exec ('dialog', '--output-fd', $outputFd,
0132                         '--backtitle', 'kdesrc-build setup',
0133                         @args);
0134     }
0135     else {
0136         die "Unable to fork? $!";
0137     }
0138 }
0139 
0140 sub getUserInput
0141 {
0142     my $prompt = shift;
0143     my $default = shift;
0144 
0145     my @args = qw/--inputbox 8 50/;
0146     splice @args, 1, 0, $prompt;
0147     push @args, $default if $default;
0148 
0149     return runDialogExecutable(@args);
0150 }
0151 
0152 sub getMenuOption
0153 {
0154     my ($prompt, @opts) = @_;
0155     @opts = @{$opts[0]} if ref $opts[0] eq 'ARRAY';
0156 
0157     my @args = qw/--menu 20 70 18/;
0158     splice @args, 1, 0, $prompt;
0159 
0160     return runDialogExecutable(@args, @opts);
0161 }
0162 
0163 sub showInfo
0164 {
0165     my $message = shift;
0166     my @args = qw/--msgbox 22 64/;
0167     splice @args, 1, 0, $message;
0168 
0169     return runDialogExecutable(@args);
0170 }
0171 
0172 sub getYesNoAnswer
0173 {
0174     my $prompt = shift;
0175     my @args = qw/--yesno 8 55/;
0176     splice @args, 1, 0, $prompt;
0177 
0178     return runDialogExecutable(@args) == 0;
0179 }
0180 
0181 sub getDirectory
0182 {
0183     my $dir = shift;
0184     my @args = qw/--dselect 10 70/;
0185     splice @args, 1, 0, $dir;
0186 
0187     return runDialogExecutable(@args);
0188 }
0189 
0190 sub getListOptions
0191 {
0192     my ($prompt, $opts, $enabled) = @_;
0193     die "\$opts not a hash ref" unless (ref $opts eq 'ARRAY');
0194     die "\$enabled not a hash ref" unless (ref $enabled eq 'HASH');
0195 
0196     my @args = qw/--checklist 20 70 18/;
0197     splice @args, 1, 0, $prompt;
0198     splice @args, 0, 0, '--output-separator', ',';
0199 
0200     while (my ($k, $v) = splice(@{$opts}, 0, 2)) {
0201         push (@args, $k, $v, (exists ${$enabled}{$k} ? 'on' : 'off'));
0202     }
0203 
0204     my $output = runDialogExecutable(@args);
0205 
0206     # Filter out empty results, remove quotes.
0207     my @items = split (/,/, $output);
0208     s/^"(.*)"$/$1/ foreach @items;
0209     @items = grep { length $_ } @items;
0210     return @items;
0211 }
0212 
0213 # The 'dialog(1)' program is required, verify it exists before going
0214 # further.
0215 # We use the --help option since it doesn't send weird terminal characters to the screen
0216 # and it's supported on dialog and Debian's dialog replacement called whiptail.
0217 system('dialog', '--help') == 0 or do {
0218     my $osError = "$!";
0219 
0220     say "Unable to run the dialog(1) program, it is required for this setup script.";
0221     if ($? == -1) {
0222         say "\tThe program wouldn't even run, due to error: $osError";
0223     }
0224     else {
0225         say "\tProgram ran, but exited with error: ", $? >> 8;
0226     }
0227 
0228     exit 1;
0229 };
0230 
0231 showInfo(<<EOF);
0232 This program sets up a base kdesrc-build configuration to
0233 use.
0234 
0235 It can be modified as you wish later. Before the form is
0236 presented, you will be asked if you would like an
0237 explanation of the kdesrc-build file layout.  It is
0238 recommended to read this if you are not already familiar
0239 with building software.
0240 EOF
0241 
0242 if (getYesNoAnswer('See the tutorial?')) {
0243     showInfo(<<EOF);
0244 kdesrc-build must download source code from the KDE
0245 repositories.  This source code is then compiled, in the
0246 "build directory". Once complete, this compiled code is
0247 installed to its final location, the "install directory".
0248 
0249 This program will only configure the install location, but
0250 all directories are configurable.
0251 
0252 The space requirements vary with the amount of software you
0253 choose to build, and whether you keep the build directories
0254 to speed up later builds.  You will probably need at least
0255 20 GiB in total free space unless you take steps to
0256 customize your install to use fewer modules.
0257 EOF
0258 }
0259 
0260 # If the user appears to be using a proxy, ask for it directly, otherwise
0261 # prompt for one.
0262 my $proxy = $ENV{http_proxy} // '';
0263 
0264 my $installDir = getMenuOption('Where do you want to install the software?',
0265     [
0266         home => "$ENV{HOME}/kde/usr (default)",
0267         custom => "Custom location, chosen next screen",
0268     ]);
0269 
0270 if ($installDir eq 'custom') {
0271     $installDir = getDirectory('/usr/local/kde');
0272 }
0273 else {
0274     $installDir = "~/kde/usr";
0275 }
0276 
0277 my $sourceDir = getMenuOption('Where do you want the source code to be saved?',
0278     [
0279         home => "$ENV{HOME}/kde/src (default)",
0280         custom => "Custom location, chosen next screen",
0281     ]);
0282 
0283 if ($sourceDir eq 'custom') {
0284     $sourceDir = getDirectory('/usr/local/kde/src');
0285 }
0286 else {
0287     $sourceDir = "~/kde/src";
0288 }
0289 
0290 my $buildDir = getMenuOption('Where do you want temporary build files to be saved? (They might need lots of space)',
0291     [
0292         home => "$ENV{HOME}/kde/build (default)",
0293         custom => "Custom location, chosen next screen",
0294     ]);
0295 
0296 if ($buildDir eq 'custom') {
0297     $buildDir = getDirectory('/usr/local/kde/build');
0298 }
0299 else {
0300     $buildDir = "~/kde/build";
0301 }
0302 
0303 showInfo(<<EOF);
0304 Should kdesrc-build automatically try to include needed KDE
0305 dependencies in each build?
0306 
0307 Doing this makes it easier to just get a single application
0308 built without worrying about the details. Most KDE software
0309 under active development needs these dependencies.
0310 IF IN ANY DOUBT, SELECT YES on the next screen.
0311 
0312 If you know exactly what you want to build or want to ensure
0313 that only modules you have allowed in your configuration
0314 file are built, then you should disable this option.
0315 
0316 You can always use the --include-dependencies or
0317 --no-include-dependencies command line option to
0318 kdesrc-build, and you can change this default at any time by
0319 editing the file that this script will generate.
0320 EOF
0321 
0322 my $includeDependencies =
0323     getYesNoAnswer('Should kdesrc-build include KDE dependencies by default with each build?');
0324 
0325 my @chosenModules = getListOptions(
0326     "Which major module groups do you want to build?",
0327     [
0328         qt5 => 'Qt 5 - Base support libraries (required if distro version is old)',
0329         frameworks => 'KDE Frameworks 5 - Essential libraries/runtime (required)',
0330         workspace => 'KDE Plasma 5 Desktop and workspace',
0331         base => 'Assorted useful KF5-based applications',
0332         pim => 'Personal Information Management software',
0333     ],
0334     {
0335         frameworks => 1,
0336         workspace => 1,
0337         base => 1,
0338     },
0339 );
0340 
0341 # According to XDG spec, if $XDG_CONFIG_HOME is not set, then we should default
0342 # to ~/.config
0343 my $xdgConfigHome = $ENV{XDG_CONFIG_HOME} // "$ENV{HOME}/.config";
0344 my $xdgConfigHomeShort = $xdgConfigHome =~ s/^$ENV{HOME}/~/r; # Replace $HOME with ~
0345 my $outputFile = "$xdgConfigHome/kdesrc-buildrc";
0346 my $outputFileShort = $outputFile =~ s/^$ENV{HOME}/~/r; # Replace $HOME with ~
0347 my $output; # Will be output filehandle.
0348 
0349 while (-e $outputFile) {
0350     my $outputChoice = getMenuOption(
0351         "$outputFileShort already exists, what do you want to do?",
0352         [
0353             backup => 'Make a backup, then overwrite with the new configuration',
0354             custom => 'Write the new configuration to a different file',
0355             cancel => 'Cancel setup',
0356         ],
0357     );
0358 
0359     if ($outputChoice eq 'cancel') {
0360         showInfo('Setup canceled');
0361         exit 0;
0362     }
0363 
0364     if ($outputChoice eq 'custom') {
0365         $outputFile = getUserInput('Enter desired configuration file name.');
0366         $outputFile =~ s/^~/$ENV{HOME}/;
0367         $outputFileShort = $outputFile =~ s/^$ENV{HOME}/~/r;
0368     }
0369 
0370     if ($outputChoice eq 'backup') {
0371         copy($outputFile, "$outputFile~") or do {
0372             my $error = "$!";
0373             showInfo(<<EOF);
0374 Failed to make backup of $outputFileShort, due to error $error.
0375 Configuration will be written to a temporary file instead.
0376 EOF
0377 
0378             ($output, $outputFile) = tempfile("kdesrc-buildrc-XXXX");
0379             $outputFileShort = $outputFile =~ s/^$ENV{HOME}/~/r;
0380         };
0381 
0382         last;
0383     }
0384 }
0385 
0386 # Filehandle could already be opened as a tempfile.
0387 if (!$output) {
0388     # Ensure the directory we need exists
0389     my ($vol, $dir, $file) = File::Spec->splitpath($outputFile);
0390     make_path($dir) unless -d $dir;
0391 
0392     open ($output, '>', $outputFile) or do {
0393         my $error = "$!";
0394         showInfo (<<EOF);
0395 Unable to open output file $outputFileShort for writing due to error $error.
0396 EOF
0397         die "$!";
0398     }
0399 }
0400 
0401 print $output <<EOF;
0402 # Autogenerated by kdesrc-build-setup. You may modify this file if desired.
0403 global
0404 EOF
0405 
0406 # Only set qtdir if we're building it ourselves. If user uses their own custom
0407 # Qt they should already be setting PATH and in that case we need do nothing
0408 # anyways.
0409 if (grep /^qt5$/, @chosenModules) {
0410     print $output <<EOF;
0411 
0412     # The path to your Qt installation (default is empty, assumes Qt provided
0413     # by system)
0414     qtdir ~/kde/qt5
0415 EOF
0416 }
0417 
0418 my $num_cores;
0419 
0420 if ($OS == 'Linux') {
0421     chomp($num_cores = `nproc`);
0422 } elsif ($OS == 'FreeBSD') {
0423     chomp($num_cores = `sysctl -n hw.ncpu`);
0424 }
0425 $num_cores ||= 4;
0426 
0427 my $num_cores_low = min(ksb::FirstRun::suggestedNumCoresForLowMemory(), $num_cores);
0428 
0429 $includeDependencies = $includeDependencies ? 'true' : 'false';
0430 
0431 #
0432 ### Start generating the kdesrc-buildrc
0433 #
0434 print $output <<EOF;
0435 
0436     # Finds and includes *KDE*-based dependencies into the build.  This makes
0437     # it easier to ensure that you have all the modules needed, but the
0438     # dependencies are not very fine-grained so this can result in quite a few
0439     # modules being installed that you didn't need.
0440     include-dependencies $includeDependencies
0441 
0442     # Install directory for KDE software
0443     kdedir $installDir
0444 
0445     # Directory for downloaded source code
0446     source-dir $sourceDir
0447 
0448     # Directory to build KDE into before installing
0449     # relative to source-dir by default
0450     build-dir $buildDir
0451 
0452    ## kdesrc-build sets 2 options which is used in options like make-options or set-env
0453     # to help manage the number of compile jobs that happen during a build:
0454     #
0455     # 1. num-cores, which is just the number of detected CPU cores, and can be passed
0456     #    to tools like make (needed for parallel build) or ninja (completely optional).
0457     #
0458     # 2. num-cores-low-mem, which is set to largest value that appears safe for
0459     #    particularly heavyweight modules based on total memory, intended for
0460     #    modules like qtwebengine
0461     num-cores $num_cores
0462     num-cores-low-mem $num_cores_low
0463 
0464     # kdesrc-build can install a sample .xsession file for "Custom"
0465     # (or "XSession") logins,
0466     install-session-driver false
0467 
0468     # or add a environment variable-setting script to
0469     # ~/.config/kde-env-master.sh
0470     install-environment-driver true
0471 
0472     # Stop the build process on the first failure
0473     stop-on-failure true
0474 
0475     # Use a flat folder layout under $sourceDir and $buildDir
0476     # rather than nested directories
0477     directory-layout flat
0478 
0479     # Build with LSP support for everything that supports it
0480     compile-commands-linking true
0481     compile-commands-export true
0482 EOF
0483 
0484 if ($proxy) {
0485     print $output <<EOF;
0486 
0487     # Proxy to use for HTTP downloads.
0488     http-proxy $proxy
0489 
0490     # Prefer HTTPS instead of Git-native protocol for git modules that come
0491     # from 'kde-projects' repositories.
0492     #
0493     # Note that any git:// repositories you use will need to be
0494     # manually converted to https:// URLs if your network does not allow
0495     # git:// protcol.
0496     git-desired-protocol https
0497 EOF
0498 }
0499 
0500 # Assume we can refer to files present alongside kdesrc-build in the source
0501 # directory
0502 my $basedir = dirname(abs_path($0));
0503 my $baseDirShort = $basedir =~ s/^$ENV{HOME}/~/r; # Replace $HOME with ~
0504 
0505 if (! -e "$basedir/kf5-frameworks-build-include") {
0506     # Check if it's installed to a share/ prefix
0507     $basedir = abs_path(dirname($0) . "/../share/kdesrc-build/");
0508     $baseDirShort = $basedir =~ s/^$ENV{HOME}/~/r;
0509 
0510     if (! -e "$basedir/kf5-frameworks-build-include") {
0511         close $output;
0512         showInfo("Unable to find kdesrc-build installation to build a configuration!");
0513         exit 1;
0514     }
0515 }
0516 
0517 print $output <<EOF;
0518 end global
0519 
0520 # Common options that should be set for some KDE modules no matter how
0521 # kdesrc-build finds them. Do not comment these out unless you know
0522 # what you are doing.
0523 include $basedir/kf5-common-options-build-include
0524 
0525 EOF
0526 
0527 my $do_incl = '#';
0528 $do_incl = '' if grep { $_ eq 'qt5' } @chosenModules;
0529 
0530 print $output <<EOF;
0531 # Refers to the qt5 file included as part of kdesrc-build. The file
0532 # is simply read-in at this point as if you'd typed it in yourself.
0533 ${do_incl}include $basedir/qt5-build-include
0534 
0535 # Support libraries that use Qt5
0536 ${do_incl}include $basedir/custom-qt5-libs-build-include
0537 
0538 EOF
0539 
0540 $do_incl = '#';
0541 $do_incl = '' if grep { $_ eq 'frameworks' } @chosenModules;
0542 
0543 print $output <<EOF;
0544 # Refers to the kf5-frameworks file included as part of kdesrc-build. The file
0545 # is simply read-in at this point as if you'd typed it in yourself.
0546 ${do_incl}include $basedir/kf5-frameworks-build-include
0547 
0548 EOF
0549 
0550 $do_incl = '#';
0551 $do_incl = '' if grep { $_ eq 'workspace' } @chosenModules;
0552 
0553 print $output <<EOF;
0554 # Refers to the kf5-workspace file included as part of kdesrc-build. The file
0555 # is simply read-in at this point as if you'd typed it in yourself.
0556 ${do_incl}include $basedir/kf5-workspace-build-include
0557 
0558 EOF
0559 
0560 $do_incl = '#';
0561 $do_incl = '' if grep { $_ eq 'base' } @chosenModules;
0562 
0563 print $output <<EOF;
0564 # Refers to the kf5-applications file included as part of kdesrc-build. The file
0565 # is simply read-in at this point as if you'd typed it in yourself.
0566 ${do_incl}include $basedir/kf5-applications-build-include
0567 
0568 EOF
0569 
0570 $do_incl = '#';
0571 $do_incl = '' if grep { $_ eq 'pim' } @chosenModules;
0572 
0573 print $output <<EOF;
0574 # Refers to the kf5-kdepim file included as part of kdesrc-build. The file
0575 # is simply read-in at this point as if you'd typed it in yourself.
0576 ${do_incl}include $basedir/kf5-kdepim-build-include
0577 
0578 EOF
0579 
0580 close($output);
0581 
0582 showInfo("Generated configuration has been written to $outputFileShort");
0583 
0584 if (!@chosenModules) {
0585     showInfo(<<EOF);
0586 You have not chosen any major module groups. You will have to
0587 add modules and module-sets to your configuration after this.
0588 
0589 To help you with this, please consult the sample files in
0590 $basedir
0591 EOF
0592 }
0593 
0594 # Say same thing in text mode just in case.
0595 system('clear');
0596 say "Generated configuration has been written to $outputFileShort";
0597 say "Sample configuration files are available in $baseDirShort";
0598 
0599 if ($outputFile ne "$xdgConfigHome/kdesrc-buildrc") {
0600     say <<EOF;
0601 
0602 Do note, that your configuration file $outputFileShort will NOT BE USED,
0603 unless you will do one of the following:
0604 - Overwrite $xdgConfigHomeShort/kdesrc-buildrc with $outputFileShort
0605 - Copy $outputFileShort to some directory and rename it to "kdesrc-buildrc",
0606   then ALWAYS run kdesrc-build from that directory
0607 - ALWAYS pass the "--rc-file $outputFileShort" option to kdesrc-build when
0608   you run it
0609 EOF
0610 }
0611 
0612 exit 0;