+sub addargs () {
+ $online //= cfg_bool qw(misc online);
+
+ if (@ARGV>=2 &&
+ $ARGV[0] =~ m{\bcargo\b}) {
+ if ($ARGV[1] =~ m/^(?:generate-lockfile|update)$/) {
+ $cargo_lock_update //= 1;
+ $target = undef;
+ }
+ if ($ARGV[1] =~ m/^(?:fetch)$/) {
+ $cargo_target_arg=0;
+ $online //= 1;
+ }
+ }
+ $cargo_lock_update //= 0;
+ $cargo_manifest_args //=
+ (defined $oot_dir) && !$cargo_lock_update;
+
+ $online //= 0;
+
+ if ($cargo_manifest_args) {
+ push @ARGV, "--manifest-path=${src_absdir}/Cargo.toml",
+ qw(--locked);
+ push @ARGV, qw(--target-dir=target) if $cargo_target_arg;
+ }
+
+ if (defined $target) {
+ if ($target =~ m{^[A-Z]}) {
+ $target = (cfgs 'arch', $target) // $archmap{$target}
+ // die "$self: --target=$target alias specified; not in cfg or map\n";
+ }
+ push @ARGV, "--target=$target";
+ }
+
+ push @ARGV, "--offline" unless $online;
+}
+
+our $oot_absdir;
+our $build_absdir; # .../Build/<subdir>
+
+sub oot_massage_cmdline () {
+ return unless defined $oot_dir;
+
+ my $use = cfgs qw(oot use);
+ $oot_absdir = ($oot_dir !~ m{^/} ? "$worksphere/" : ""). $oot_dir;
+ $build_absdir = "$oot_absdir/$subdir";
+
+ my ($pre,$post);
+ my @xargs;
+ if (!$cargo_lock_update) {
+ push @xargs, $build_absdir;
+ ($pre, $post) = ('cd "$1"; shift; ', '');
+ } else {
+ push @xargs, $oot_absdir, $subdir, $src_absdir;
+ $pre = <<'END';
+ cd "$1"; shift;
+ mkdir -p -- "$1"; cd "$1"; shift;
+ cp -- "$1"/Cargo.toml
+END
+ $pre .= <<'ENDLK' if stat_exists 'Cargo.lock', 'working cargo lockfile';
+ "$1"/Cargo.lock
+ENDLK
+ $pre .= <<'ENDCP';
+ .;
+ENDCP
+ $pre .= <<'ENDPRE';
+ shift;
+ mkdir -p src; >src/lib.rs; >build.rs
+ENDPRE
+ $post = <<'ENDPOST';
+ rm -r src Cargo.toml build.rs;
+ENDPOST
+ }
+ my $addpath = (cfg_uc qw(oot path_add)) //
+ $use eq 'really' ? Types::Serialiser::true : Types::Serialiser::false;
+ $addpath =
+ !Types::Serialiser::is_bool $addpath ? $addpath :
+ $addpath ? '$HOME/.cargo/bin' :
+ undef;
+ if (defined $addpath) {
+ $pre .= <<END
+ PATH=$addpath:\${PATH-/usr/local/bin:/bin:/usr/bin};
+ export PATH;
+END
+ }
+ $pre =~ s/^\s+//mg; $pre =~ s/\s+/ /g;
+ $post =~ s/^\s+//mg; $post =~ s/\s+/ /g;
+
+ my $getuser = sub { cfgsn qw(oot user) };
+ my @command;
+ my $xe = $verbose >= 2 ? 'xe' : 'e';
+ my $sh_ec = sub {
+ if (!length $post) {
+ @command = (@_, 'sh',"-${xe}c",$pre.'exec "$@"','--',@xargs);
+ } else {
+ @command = (@_, 'sh',"-${xe}c",$pre.'"$@"; '.$post,'--',@xargs);
+ }
+ push @command, @ARGV;
+ };
+ my $command_sh = sub {
+ my $quoted = join ' ', map {
+ return $_ if !m/\W/;
+ s/\'/\'\\'\'/g;
+ "'$_'"
+ } @ARGV;
+ @command = @_, "set -${xe}; $pre $quoted; $post";
+ };
+ print STDERR "$self: out-of-tree, building in: \`$build_absdir'\n"
+ if $verbose;
+ if ($use eq 'really') {
+ my $user = $getuser->();
+ my @pw = getpwnam $user or die "$self: oot.user \`$user' lookup failed\n";
+ my $homedir = $pw[7];
+ $sh_ec->('really','-u',$user,'env',"HOME=$homedir");
+ print STDERR "$self: using really to run as user \`$user'\n" if $verbose;
+ } elsif ($use eq 'ssh') {
+ my $user = $getuser->();
+ $user .= '@localhost' unless $user =~ m/\@/;
+ $command_sh->('ssh',$user);
+ print STDERR "$self: using ssh to run as \`$user'\n" if $verbose;
+ } elsif ($use eq 'command_args') {
+ my @c = cfgn_list qw(oot command);
+ $sh_ec->(@c);
+ print STDERR "$self: out-of-tree, adverbial command: @c\n" if $verbose;
+ } elsif ($use eq 'command_sh') {
+ my @c = cfgn_list qw(oot command);
+ $command_sh->(@c);
+ print STDERR "$self: out-of-tree, ssh'ish command: @c\n" if $verbose;
+ } elsif ($use eq 'null') {
+ $sh_ec->();
+ } else {
+ die "$self: oot.use mode $use not recognised\n";
+ }
+ die unless @command;
+ @ARGV = @command;
+}
+
+sub setenvs () {
+ $ENV{NAILINGCARGO_WORKSPHERE} = $worksphere;
+ $ENV{NAILINGCARGO_MANIFEST_DIR} = $src_absdir;
+ $ENV{NAILINGCARGO_BUILDSPHERE} = $oot_absdir;
+ delete $ENV{NAILINGCARGO_BUILDSPHERE} unless $oot_absdir;
+ $ENV{NAILINGCARGO_BUILD_DIR} = $build_absdir // $src_absdir;
+}
+