chiark / gitweb /
New scheme for subcommand handling - wip
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 21 Jun 2020 12:43:14 +0000 (13:43 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 21 Jun 2020 12:43:14 +0000 (13:43 +0100)
Does not work yet.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
README.md
nailing-cargo

index 28db3679ef25eaef0f405ac86dfc1fa67b5fc49b..f989ab6b2427bc629db899d2ca2102159f7a32d5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -264,7 +264,7 @@ Options
        then in the builtin arch alias list.  The builtin list is
        equivalent to: `[arch]` `RPI='arm-unknown-linux-gnueabihf'`.
 
-  * `-c<subcommand>`
+  * `-s<subcommand>`
 
        Behave as if the build command were `cargo <subcommand>`.
        This influences the logic which tries to determine which
@@ -272,29 +272,31 @@ Options
        whether cargo might want to update `Cargo.lock`.
 
        nailing-cargo knows about `update`, `generate-lockfile` and
-       `fetch`; all other subcommands are (silently) treated the
-       same way as `build`.  See `--subcommand-props`, below, for
-       more detail about how the subcommand affects nailing-cargo's
-       behaviour.
+       `fetch`; all other subcommands are (silently) treated the same
+       way as `build` (ie, no subcommand properties).  See
+       `--subcommand-props`, below, for more detail about how the
+       subcommand affects nailing-cargo's behaviour.
 
        This option does not affect which build command (and which
-       cargo subcommand) is actually run.
-       The default is to look into the command line to find the cargo
-       subcommand.
-
-  * `-C`
-
-       Behave as if the build command will not run cargo.
-
-       This suppresses the addition of cargo command line options and
-       makes nailing-cargo assumes that the build command will not
-       need to update `Cargo.lock`.
-       But this option does not affect which build command is actually
-       run.
-
-       The default is to treat the build command as cargo unless a
-       build command is specified whose leafname does not contains the
-       string `cargo`.
+       cargo subcommand) is actually run.  The default is to use the
+       cargo subcommand found from parsing nailing-cargo's
+       command line.
+
+  * `-c` | `-C`
+
+       Controls the addition of cargo command line options; ie,
+       whether nailing-cargo should treat the build command as if it
+       were cargo.
+       With `-C`, nailing-cargo will not add additional options
+       to the build command.  With `-c` it will pass those options
+       at the end of the build command.
+       The cargo options are in any case also passed in the
+       environment - see [Environment of the build command].
+
+       The default is to pass cargo options if the command line
+       parsing yielded a cargo command and options (usages 1 and 2),
+       rather than a non-cargo build command (usage 3).  `-C` and `-c`
+       do not affect the parsing of nailing-cargo's command line.
 
   * `-o` | `--online` | `-O` | `--offline`
 
@@ -320,32 +322,53 @@ Options
   * `--subcommand-props=<prop>,...`
 
        Specify the properties of the subcommand.  This is an
-       alternative to `-c<subcmd>`.  The properties are:
+       alternative to `-s<subcmd>`.  The usual properties are:
 
     * `lock_update`: cargo will want to update `Cargo.lock`.  (The `-u` and `-U` options override this.)
     * `online`: this subcommand makes no sense to run offline.  (The `-o` and `-O` options, and the configuration, can override this.)
     * `!target`: cargo would reject `--target=<arch>`; in this case nailing-cargo's `-T` option is ineffective.
     * `!target-dir`: cargo would reject `--target-dir`, so don't pass it.  (Usually we pass `--target-dir=target` when we pass `--manifest-path`, since cargo's default is `target` in the same directory as `Cargo.toml`.)
-    * `!manifest-path`: cargo would reject `--manifest-path`, so don't pass it (and don't pass `--target-dir` either).  Only makes any difference for out-of-tree builds.  Things will probably go wrong unless the build command looks at `NAILINGCARGO_MANIFEST_DIR`.
-    * `!locked`: cargo would reject `--locked`, so don't pass it (hazardous).
-    * `!offline`: the build command would reject `--offline`, so never pass it.  *Not* overridden by configuration or command line.  Primarily for non-cargo build commands.
+
+    There are also some properties which should not be needed, but are
+    provided for completeness.  Do not use these to solve the problem
+    of nailing-cargo passing cargo options to a build command which is
+    not cargo - use `-C` for that.  The properties whose use is discouraged:
+
+    * `!manifest-path`: cargo would reject `--manifest-path`, so don't pass it (and don't pass `--target-dir` either).  Only makes any difference for out-of-tree builds.  Things will probably go wrong unless the build command looks at `[NAILING]CARGO_MANIFEST_DIR`.
+    * `!locked`: cargo would reject `--locked`, so don't pass it.  Hazardous.
+    * `!offline`: the build command would reject `--offline`, so never pass it.  *Not* overridden by configuration or command line.
 
 Environment of the build command
 --------------------------------
 
 nailing-cargo passes these environment variables to the build command:
 
+  * `CARGO_MANIFEST_DIR`: invocation `.` (invocation directory)
+  * `NAILINGCARGO_MANIFEST_DIR`: same as `CARGO_MANIFEST_DIR`
   * `NAILINGCARGO_WORKSPHERE`: invocation `..` (parent)
-  * `NAILINGCARGO_MANIFEST_DIR`: invocation `.` (invocation directory)
   * `NAILINGCARGO_BUILD_DIR`: build directory (even if same as source)
-  * `NAILINGCARGO_BUILDSPHERE`: only set if out of tree: parent of build dir.
+  * `NAILINGCARGO_BUILDSPHERE`: parent of build dir (only set if out-of-tree)
+  * `NAILINGCARGO_CARGO_OPTIONS`: additional options that nailing-cargo passed (or would pass) to cargo.  Space-separated; does not include `--manifest-path`.
 
 All of these are absolute paths.
 
-For out-of-tree builds it is always necessary to pass --manifest-path
-to cargo, so non-cargo build commands will need to look at
-`NAILINGCARGO_MANIFEST_DIR` and turn that back into a cargo option;
-they may also need to pass `--target-dir=<target>`.
+### Build commands which wrap cargo ###
+
+If you specify a build command which eventually runs cargo, you may
+wish to pass on to your cargo the options which nailing-cargo would
+have passed.  This will definitely be necessary if you are using nailing-cargo's out-of-tree facility.
+
+In such a situation, do it like this:
+```
+  cargo build --manifest-path="${CARGO_MANIFEST_DIR-.}"/Cargo.toml $NAILINGCARGO_CARGO_OPTIONS
+```
+
+If you need to run a cargo subcommand which doesn't understand some of
+nailing-cargo's options, currently, you must strip them out of
+`NAILINGCARGO_CARGO_OPTIONS` yourself - or pass some `-s` or
+`--subcmd-props` option to nailing-cargo (but that is a layering
+violation and may not work if one build command runs various different
+cargo runes).
 
 Configuration reference
 =======================
@@ -490,7 +513,7 @@ Limitations and bugs
   * nailing-cargo needs to understand the behaviour of the cargo
     subcommand you are running - especially for out-of-tree builds.
     nailing-cargo only has a short builtin list of commands it knows
-    about (see the `-c` option).  For other commands, you may need to
+    about (see the `-s` option).  For other commands, you may need to
     add an entry to `@subcmd_propss` in the source, or use
     `--subcommand-props`.
 
index 829d279889d94d447900c4f884e5554a87b5e51c..58a777e75062ab91480c00b79a6741bd1ace9da0 100755 (executable)
@@ -44,17 +44,19 @@ our $subdir = $1; # leafname
 our $lockfile = "../.nailing-cargo.lock";
 
 our $cargo_subcmd;
+our $command_is_cargo;
 our $alt_cargo_lock;
 our $online;
 
 #
 our %subcmd_props = {
 # build (default)  =>qw(                                        ),
- update            =>qw( !target lock-update                    ),
-'generate-lockfile'=>qw( !target lock-update                    ),
- fetch             =>qw( !target             online !target-dir ),
- ''                =>qw( !target !manifest-path !locked !offline );
-};
+ update            =>qw( lock-update !target                    ),
+'generate-lockfile'=>qw( lock-update !target                    ),
+ fetch             =>qw(             !target online !target-dir ),
+                   };
+
+our @subcmd_xprops = qw(!manifest-path !offline !locked);
 
 our @configs;
 our $verbose=1;
@@ -359,11 +361,13 @@ sub addargs () {
 
   $cargo_lock_update //= subcmd_p('lock-update');
 
+  our @add;
+
   if (!$cargo_lock_update) {
-    push @ARGV, qw(--locked) unless subcmd_p('!locked');
+    push @add, qw(--locked) unless subcmd_p('!locked');
     if (defined($oot_dir) && !subcmd_p('!manifest-path')) {
-      push @ARGV, "--manifest-path=${src_absdir}/Cargo.toml";
-      push @ARGV, qw(--target-dir=target) unless subcmd_p('!target');
+      push @ARGV, "--manifest-path=${src_absdir}/Cargo.toml" if $pass_options;
+      push @add, qw(--target-dir=target) unless subcmd_p('!target');
     }
   }
 
@@ -372,10 +376,14 @@ sub addargs () {
       $target = (cfgs 'arch', $target) // $archmap{$target}
        // die "$self: --target=$target alias specified; not in cfg or map\n";
     }
-    push @ARGV, "--target=$target";
+    push @add, "--target=$target";
   }
 
-  push @ARGV, "--offline" unless $online || subcmd_p('!offline');
+  push @add, "--offline" unless $online || subcmd_p('!offline');
+
+  push @ARGV, @add if $pass_options;
+  die if grep { m/ / } @add;
+  $ENV{NAILINGCARGO_CARGO_OPTIONS} = "@add";
 }
 
 our $oot_absdir;
@@ -479,8 +487,9 @@ END
 }
 
 sub setenvs () {
-  $ENV{NAILINGCARGO_WORKSPHERE}   = $worksphere;
+  $ENV{CARGO_MANIFEST_DIR} = $src_absdir;
   $ENV{NAILINGCARGO_MANIFEST_DIR} = $src_absdir;
+  $ENV{NAILINGCARGO_WORKSPHERE}   = $worksphere;
   $ENV{NAILINGCARGO_BUILDSPHERE}  = $oot_absdir;
   delete $ENV{NAILINGCARGO_BUILDSPHERE} unless $oot_absdir;
   $ENV{NAILINGCARGO_BUILD_DIR}    = $build_absdir // $src_absdir;
@@ -685,16 +694,16 @@ sub parse_args () {
          $verbose=0;
        } elsif (s{^-n}{-}) {
          $noact++;
-       } elsif (s{^-c(.+)}{-}s) {
+       } elsif (s{^-s(.+)}{-}s) {
          $cargo_subcmd = $1;
-       } elsif (s{^-C}{-}) {
-         $cargo_subcmd = '';
+       } elsif (s{^-([cC])}{-}) {
+         $pass_options = $1=~m/[a-z]/;
        } elsif (s{^-D}{-}) {
          $dump++;
        } elsif (s{^-T(.+)}{-}s) {
          $target = $1;
        } elsif (s{^-([oO])}{-}) {
-         $online= $1=~m/[a-z]/;
+         $online = $1=~m/[a-z]/;
        } else {
          die "$self: unknown short option(s) $_\n" unless $_ eq $orgopt;
          $not_a_nailing_opt->();
@@ -708,7 +717,9 @@ sub parse_args () {
       my @props = split /\,/, $_;
       our %subcmd_prop_ok;
       if (!%subcmd_prop_ok) {
-       for $v in (%subcmd_props) { $subcmd_prop_ok{$_}=1 foreach @$v; };
+       for $v in (\@subcmd_xprops, values %subcmd_props) {
+         $subcmd_prop_ok{$_}=1 foreach @$v;
+       };
       }
       $subcmd_prop_ok{$_}
        or die "$self: unknown subcommand property \`$_'\n"
@@ -733,9 +744,11 @@ sub parse_args () {
     }
     @ARGV || die "$self: need cargo subcommand\n";
     $cargo_subcmd //= $ARGV[0];
+    $pass_options //= 1;
     unshift @ARGV, @cargo_and_opts;
   } else {
     $cargo_subcmd //= '';
+    $pass_options //= 0;
   }
 
   if (!ref($cargo_subcmd)) {