App::C...d::run(3pm)

🌸 App::Cme::Command::run

okay so bestie, this is the App::C...d::run(3pm) manual page πŸ’– β€” yeah the title got chopped by your terminal, it's giving "my window is this small" energy πŸ’€. The real name is App::Cme::Command::run, and we are about to run some cme scripts together. Grab a boba πŸ§‹, sit criss-cross, let's go.


πŸŽ€ NAME

App::Cme::Command::run - Run a cme script

✨ VERSION

version 1.049

πŸ¦‹ SYNOPSIS

okay so first, a little main-character demo of what a cme script even is. Watch this:

$ cat ~/.cme/scripts/remove-mia
doc: remove mia from Uploaders. Require mia parameter
# declare app to configure
app: dpkg
# specify one or more instructions
load: ! control source Uploaders:-~/$mia$/
# commit the modifications with a message (git only)
commit: remove MIA dev $mia

$ cme run remove-mia -arg mia=longgone@d3bian.org

# cme run can also use environment variables
$ cat ~/.cme/scripts/add-me-to-uploaders
app: dpkg-control
load: source Uploaders:.push("$DEBFULLNAME <$DEBEMAIL>")

$ cme run add-me-to-uploaders
Reading package lists... Done
Building dependency tree
Reading state information... Done
Changes applied to dpkg-control configuration:
- source Uploaders:3: '<undef>' -> 'Dominique Dumont <dod@debian.org>'

# show the script documentation
$ cme run remove-mia -doc
remove mia from Uploaders. require mia parameter

# list scripts
$ cme run -list
Available scripts:
- update-copyright
- add-me-to-uploaders

# mass modification
$ cme run add-me-to-uploaders --foreach "raku-log raku-zef"
# similar result
$ echo "raku-*" | cme run add-me-to-uploaders --foreach -

ate, no crumbs πŸ”₯.

πŸ’– DESCRIPTION

It runs a script written for cme. That's it. That's the vibe.

So, if you hand it a script by name, cme goes hunting through ~/.cme/scripts, /etc/cme/scripts or /usr/share/perl5/Config/Model/scripts πŸ”. Like, say you type cme run foo β€” then cme loads whichever of these it finds first: ~/.cme/scripts/foo, /etc/cme/scripts/foo or /usr/share/perl5/Config/Model/scripts/foo.

But the second you pass an actual path, the searching stops. No search, no scavenger hunt. E.g. cme run ./foo β€” it just uses what you gave it, periodt.

cme run is super open-minded and accepts scripts written in a bunch of different syntaxes:

🧚 cme DSL

For simple scripts! This DSL text specifies the target app, the doc, optional variables and a load string used by Config::Model::Loader or Perl code.

🌈 YAML

Exactly like the text above, but using Yaml syntax. Same energy, different font.

πŸ’œ Perl data structure

Writing Perl code in a text file or in a YAML field can be painful 😭 β€” because Perl syntax doesn't get highlighted. Rude. So with a Perl data structure, a cme script specifies the target app, the doc, optional variables, and a perl subroutine (more on that below, bestie πŸ‘‡).

⭐ plain Perl script

cme run can also run a plain Perl script. It's basically syntactic sugar so you don't go polluting the global namespace β€” i.e. there's no need to store a script using cme function in /usr/local/bin/. But heads up: the script must begin with the usual shebang line (#!) and be executable. Non-negotiable, that's the law πŸ’….

And to help management with cme run, here's the deal:

  • comment lines beginning with ## are shown as doc (with cme run xxx --doc)
  • comment line beginning with # app: indicates the app shown by cme run --list command

So when run, this script:

  • opens the configuration file of app
  • applies the modifications specified with load instructions or the Perl code.
  • save the configuration files
  • commits the result if commit is specified (either in script or on command line).

See App::Cme::Command::run for details.


πŸŽ€ Syntax of text format

The script accepts instructions in the form:

key: value

The key line can be repeated when needed. Yes queen, repeat yourself πŸ’….

Multi line values can also be:

--- key
multi line value
---

The script accepts the following instructions:

πŸ’… app

Specify the target application. Must be one of the application listed by cme list command. Mandatory. Only one app instruction is allowed. One app only, we don't do polyamory here πŸ™ˆ.

πŸ“ default

Specify default values that can be used in load or var sections.

For instance:

default: name=foobar

🌸 var

Use Perl code to specify variables usable in this script. The Perl code must store data in %var hash. For instance:

var: my @l = localtime; $var{year} =  $l[5]+1900;

The hash %args contains the variables passed with the -arg option. Reading a value from %args which is not set by user triggers a missing option error 🚨. Use exists if you need to test if a argument was set by user:

var: $var{foo} = exists $args{bar} ? $args{bar} : 'default' # good
var: $var{foo} = $args{bar} || 'default' # triggers a "missing arg" error

See that second one? That's the villain origin story. Don't do it πŸ’€.

πŸ¦‹ load

Specify the modifications to apply using a string as specified in Config::Model::Loader. This string can contain variable (e.g. $foo) which are replaced by command argument (e.g. -arg foo=bar) or by a variable set in var: line (e.g. $var{foo} as set above) or by an environment variable (e.g. $ENV{foo}).

πŸ‘‘ code

Specify Perl code to run. See "code section" for details.

πŸ”₯ commit

Specify that the change must be committed with the passed commit message. When this option is used, cme stashes and restores all modifications if used on a non-clean workspace. This option works only with git. (git girlies rise 🫢)

Strings like {{ load path }} are substituted with a value extracted from configuration tree with the specified load path. See Config::Model::Loader for a valid load path.

For example, this specification:

load: source Standards-Version="4.7.0"
commit: declare compliance with policy {{source Standards-Version}}

yields this commit message:

declare compliance with policy 4.7.0

String like $some_value are with substituted with a value coming from an environment variable, a script argument or a value defined as a var line.

For example, this specification:

var: $var{close_str} = defined $args{closes} ? " (Closes: #$args{closes})" : ""
commit: set $DEBEMAIL as Maintainer$close_str

invoked with argument -arg closes=1234, yields this commit message:

set dod@example.com as Maintainer (Closes: #1234)

Iconic. No notes. ✨

All instructions can use variables like $stuff whose value can be specified with -arg options, with a Perl variable (from var: section explained above) or with an environment variable:

For instance:

cme run -arg var1=foo -arg var2=bar

transforms the instruction:

load: ! a=$var1 b=$var2

in

load: ! a=foo b=bar

Like, it literally just does the swap. So satisfying 😌.

πŸ’œ Example

Here's an example from libconfig-model-dpkg-perl scripts (https://salsa.debian.org/perl-team/modules/packages/libconfig-model-dpkg-perl/-/blob/master/lib/Config/Model/scripts/add-me-to-uploaders):

doc: add myself to Uploaders
app: dpkg-control
load: source Uploaders:.insort("$DEBFULLNAME <$DEBEMAIL>")
commit: add $DEBEMAIL to Uploaders

You can find other examples on script directory of libconfig-model-dpkg-perl (https://salsa.debian.org/perl-team/modules/packages/libconfig-model-dpkg-perl/-/blob/master/lib/Config/Model/scripts/)

🧚 Code section

The code section can contain variable (e.g. $foo) which are replaced by command argument (e.g. -arg foo=bar) or by a variable set in var: line (e.g. $var{foo} as set above).

When evaluated the following variables are also set:

  • $root β€” Root node of the configuration (See Config::Model::Node)
  • $inst β€” Configuration instance (See Config::Model::Instance)
  • $commit_msg β€” Message used to commit the modification.

Since the code is run in an eval, other variables are available (like $self) to shoot yourself in the foot. πŸ’€ yeah, foot-shooting privileges included, no extra charge.

For example:

app:  popcon
---code
$root->fetch_element('MY_HOSTID')->store($to_store);
---

🌈 Syntax of YAML format

This format is intented for people not wanting to user the text format above. It supports the same parameters as the text format. (Yes, "intented" and "user" β€” that's how it's written, I don't make the rules πŸ™ˆ.)

When using ! and $ characters in a string, using YAML block scalar is probably easier.

For instance:

# Format: YAML
---
app: popcon
default:
  defname: foobar
var: |-
  $var{name} = $args{defname}
load: |-
  ! MY_HOSTID=$name

⭐ Syntax of Perl format

This format is intended for more complex script where using load instructions is not enough.

This script must then begin with # Format: perl and specifies a hash. For instance:

# Format: perl
{
     app => 'popcon', # mandatory
     doc => "Use --arg to_store=a_value to store a_value in MY_HOSTID',
     commit => "control: update Vcs-Browser and Vcs-Git"
     sub => sub ($root, $arg) { $root->fetch_element('MY_HOSTID')->store($arg->{to_store}); }
}

$root is the root if the configuration tree (See Config::Model::Node). $arg is a hash containing the arguments passed to cme run with -arg options.

The sub parameter value must be a sub ref. Its parameters are $root (a Config::Model::Node object containing the root of the configuration tree) and $arg (a hash ref containing the keys and values passed to cme run with --arg options).

Note that this format does not support var, default and load parameters as you can easily achieve the same result with Perl code. πŸ’…


πŸ‘‘ Options

πŸ’– list

List available scripts and exits.

πŸŽ€ arg

Arguments for the cme scripts which are used to substitute variables.

🌸 doc

Show the script documentation. (Note that --help options show the documentation of cme run command)

πŸ¦‹ cat

Pop the hood and show the content of the script. πŸ”

πŸ”₯ commit

Like the commit instruction in script. Specify that the change must be committed with the passed commit message.

πŸ’€ no-commit

Don't commit to git (even if the above option is set). Boundaries, bestie. βœ‹

⭐ foreach

Apply the script in specific directories. This option is available only when dealing with application (See the list returned by cme list).

For instance, if your directory contains several Debian packages and you want to apply the same modification to all packages, you can run something like:

   cme run add-me-to-uploaders --foreach "raku-log raku-zef"

or use STDIN to send the package directories:

   ls "raku-*" | cme run add-me-to-uploaders --foreach -

Mass modification, but make it a serve 😌.

πŸ’œ verbose

Show effect of the modify instructions.

🌈 Common options

See "Global Options" in cme.

okay so imagine you're a Debian maintainer and it's January and the copyright years are stale β€” bestie, this is the script that fixes that. Look:

$ cme run update-copyright -cat
app: dpkg-copyright
load: Files:~ Copyright=~"s/2016,?\s+$name/2017, $name/g"
commit: updated copyright year of $name

the -cat there is just showing you what the script says, she's not doing anything yet πŸ’… and then you actually run it and pass your name in like this:

$ cme run update-copyright -arg "name=Dominique Dumont"
cme: using Dpkg::Copyright model
Changes applied to dpkg-copyright configuration:
- Files:"*" Copyright: '2005-2016, Dominique Dumont <dod@debian.org>' -> '2005-2017, Dominique Dumont <dod@debian.org>'
- Files:"lib/Dpkg/Copyright/Scanner.pm" Copyright:
@@ -1,2 +1,2 @@
-2014-2016, Dominique Dumont <dod@debian.org>
+2014-2017, Dominique Dumont <dod@debian.org>
  2005-2012, Jonas Smedegaard <dr@jones.dk>

[master ac2e6410] updated copyright year of Dominique Dumont
 1 file changed, 2 insertions(+), 2 deletions(-)

see how it literally shows you the diff before committing?? that's the vibe check passing βœ… and then boom, a real commit at the bottom. iconic.


🌸 update VcsGit in debian/control 🌸

next up, the "please stop hand-editing the Vcs- fields" script:

$ cme run set-vcs-git  -cat
doc: update control Vcs-Browser and Vcs-git from git remote value
doc: parameters: remote (default is origin)
doc:
doc: example:
doc:  cme run set-vcs-git
doc:  cme run set-vcs-git -arg remote=debian

app: dpkg-control
default: remote: origin

var: chomp ( $var{url} = `git remote get-url $args{remote}` ) ;
var: $var{url} =~ s!^git@!https://!;
var: $var{url} =~ s!(https?://[\w.]+):!$1/!;
var: $var{browser} = $var{url};
var: $var{browser} =~ s/.git$//;

load: ! source Vcs-Browser="$browser" Vcs-Git="$url"
commit: control: update Vcs-Browser and Vcs-Git

like. she reads your git remote, cleans it up, turns it into a browsable URL, and writes it into debian/control. no cap, that's the whole job 🫢

and the same script can be written with multi line instructions instead β€” look at this glow-up:

$ cme run set-vcs-git  -cat
--- doc
update control Vcs-Browser and Vcs-git from git remote value
parameters: remote (default is origin)

example:
 cme run set-vcs-git
 cme run set-vcs-git -arg remote=debian
---

app: dpkg-control
default: remote: origin

--- var
chomp ( $var{url} = `git remote get-url $args{remote}` ) ;
$var{url} =~ s!^git@!https://!;
$var{url} =~ s!(https?://[\w.]+):!$1/!;
$var{browser} = $var{url};
$var{browser} =~ s/.git$//;
---

load: ! source Vcs-Browser="$browser" Vcs-Git="$url"
commit: control: update Vcs-Browser and Vcs-Git

same energy, way better formatting, she ate πŸ’–


πŸ’œ personal scripts πŸ’œ

and NOW the best part β€” you can write your own scripts and drop them in ~/.cme/scripts. here's a whole example, literally the entire file:

$ cat ~/.cme/scripts/set-any-arch
app: dpkg-control
load: binary:~".*" Architecture=any

tiny. adorable. devastating. that's a script that sets every binary package's Architecture to any. main character energy fr fr πŸ‘‘


πŸ” SEE ALSO

  • cme

(yeah that's it, she's self-referential, she contains multitudes)


✍️ AUTHOR

Dominique Dumont


This software is Copyright (c) 2014-2022 by Dominique Dumont <ddumont@cpan.org>.

This is free software, licensed under:

The GNU Lesser General Public License, Version 2.1, February 1999

and that's a wrap bestie πŸŽ€βœ¨ you made it to the end of part 2, I'm so proud of you πŸ˜­πŸ’– this page is perl v5.40.1 flavored, dated 2026-06-29, and it's the App::C...d::run(3pm) page β€” go forth and cme run something slay today πŸ’…πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from