Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
App::Sqitch::Plan(3)  User Contributed Perl Documentation App::Sqitch::Plan(3)

       App::Sqitch::Plan - Sqitch Deployment Plan

	 my $plan = App::Sqitch::Plan->new( sqitch => $sqitch );
	 while (my $change = $plan->next) {
	     say "Deploy ", $change->format_name;

       App::Sqitch::Plan provides the interface	for a Sqitch plan. It parses a
       plan file and provides an iteration interface for working with the


       Returns the current version of the Sqitch plan syntax. Used for the
       "%sytax-version"	pragma.

   Class Methods

	 die "$this has	no name" unless	$this =~ App::Sqitch::Plan->name_regex;

       Returns a regular expression that matches names.	Note that it is	not
       anchored, so if you need	to make	sure that a string is a	valid name and
       nothing else, you will need to anchor it	yourself, like so:

	   my $name_re = App::Sqitch::Plan->name_regex;
	   die "$this is not a valid name" if $this !~ /\A$name_re\z/;


	 my $plan = App::Sqitch::Plan->new( sqitch => $sqitch );

       Instantiates and	returns	a App::Sqitch::Plan object. Takes a single
       parameter: an App::Sqitch object.


	 my $sqitch = $plan->sqitch;

       Returns the App::Sqitch object that instantiated	the plan.


	 my $target = $plan->target

       Returns the App::Sqitch::Target passed to the constructor.


	 my $file = $plan->file;

       The file	name from which	to read	the plan.


       Returns the current position of the iterator. This is an	integer	that's
       used as an index	into plan. If "next()" has not been called, or if
       "reset()" has been called, the value will be -1,	meaning	it is outside
       of the plan. When "next"	returns	"undef", the value will	be the last
       index in	the plan plus 1.


	 my $project = $plan->project;

       Returns the name	of the project as set via the %project pragma in the
       plan file.


	 my $uri = $plan->uri;

       Returns the URI for the project as set via the %uri pragma, which is
       optional. If it is not present, "undef" will be returned.


	 my $syntax_version = $plan->syntax_version;

       Returns the plan	syntax version,	which is always	the latest version.

   Instance Methods

	 my $index	= $plan->index_of('6c2f28d125aff1deea615f8de774599acf39a7a1');
	 my $foo_index	= $plan->index_of('@foo');
	 my $bar_index	= $plan->index_of('bar');
	 my $bar1_index	= $plan->index_of('bar@alpha')
	 my $bar2_index	= $plan->index_of('bar@HEAD');

       Returns the index of the	specified change. Returns "undef" if no	such
       change exists. The argument may be any one of:

       o   An ID

	     my	$index = $plan->index_of('6c2f28d125aff1deea615f8de774599acf39a7a1');

	   This	is the SHA1 hash of a change or	tag. Currently,	the full
	   40-character	hexed hash string must be specified.

       o   A change name

	     my	$index = $plan->index_of('users_table');

	   The name of a change. Will throw an exception if the	named change
	   appears more	than once in the list.

       o   A tag name

	     my	$index = $plan->index_of('@beta1');

	   The name of a tag, including	the leading "@".

       o   A tag-qualified change name

	     my	$index = $plan->index_of('users_table@beta1');

	   The named change as it was last seen	in the list before the
	   specified tag.


	 say 'Yes!' if $plan->contains('6c2f28d125aff1deea615f8de774599acf39a7a1');

       Like "index_of()", but never throws an exception, and returns true if
       the plan	contains the specified change, and false if it does not.


	 my $change = $plan->get('6c2f28d125aff1deea615f8de774599acf39a7a1');
	 my $foo    = $plan->get('@foo');
	 my $bar    = $plan->get('bar');
	 my $bar1   = $plan->get('bar@alpha')
	 my $bar2   = $plan->get('bar@HEAD');

       Returns the change corresponding	to the specified ID or name. The
       argument	may be in any of the formats described for "index_of()".


	 my $change = $plan->find('6c2f28d125aff1deea615f8de774599acf39a7a1');
	 my $foo    = $plan->find('@foo');
	 my $bar    = $plan->find('bar');
	 my $bar1   = $plan->find('bar@alpha')
	 my $bar2   = $plan->find('bar@HEAD');

       Finds the change	corresponding to the specified ID or name. The
       argument	may be in any of the formats described for "index_of()".
       Unlike "get()", "find()"	will not throw an error	if more	than one
       change exists with the specified	name, but will return the first


	 my $index = $plan->first_index_of($change_name);
	 my $index = $plan->first_index_of($change_name, $change_or_tag_name);

       Returns the index of the	first instance of the named change in the
       plan. If	a second argument is passed, the index of the first instance
       of the change after the index of	the second argument will be returned.
       This is useful for getting the index of a change	as it was deployed
       after a particular tag, for example, to get the first index of the foo
       change since the	@beta tag, do this:

	 my $index = $plan->first_index_of('foo', '@beta');

       You can also specify the	first instance of a change after another
       change, including such a	change at the point of a tag:

	 my $index = $plan->first_index_of('foo', 'users_table@beta1');

       The second argument must	unambiguously refer to a single	change in the
       plan. As	such, it should	usually	be a tag name or tag-qualified change
       name. Returns "undef" if	the change does	not appear in the plan,	or if
       it does not appear after	the specified second argument change name.


	 my $change = $plan->last_tagged_change;

       Returns the last	tagged change object. Returns "undef" if no changes
       have been tagged.


	 my $change = $plan->change_at($index);

       Returns the change at the specified index.



       Move the	plan position to the specified change. Dies if the change
       cannot be found in the plan.



       Resets iteration. Same as "$plan->position(-1)",	but better.


	 while (my $change = $plan->next) {
	     say "Deploy ", $change->format_name;

       Returns the next	change in the plan. Returns "undef" if there are no
       more changes.


	 my $change = $plan->last;

       Returns the last	change in the plan. Does not change the	current


	  my $change = $plan->current;

       Returns the same	change as was last returned by "next()". Returns
       "undef" if "next()" has not been	called or if the plan has been reset.


	  my $change = $plan->peek;

       Returns the next	change in the plan without incrementing	the iterator.
       Returns "undef" if there	are no more changes beyond the current change.


	 my @changes = $plan->changes;

       Returns all of the changes in the plan. This constitutes	the entire


	 my @tags = $plan->tags;

       Returns all of the tags in the plan.


	 my $count = $plan->count;

       Returns the number of changes in	the plan.


	 my @lines = $plan->lines;

       Returns all of the lines	in the plan. This includes all the changes,
       tags, pragmas, and blank	lines.


	 $plan->do(sub { say $_[0]->name; return $_[0];	});
	 $plan->do(sub { say $_->name;	  return $_;	});

       Pass a code reference to	this method to execute it for each change in
       the plan.  Each change will be stored in	$_ before executing the	code
       reference, and will also	be passed as the sole argument.	If "next()"
       has been	called prior to	the call to "do()", then only the remaining
       changes in the iterator will passed to the code reference. Iteration
       terminates when the code	reference returns false, so be sure to have it
       return a	true value if you want it to iterate over every	change.


	 my $iter = $engine->search_changes( %params );
	 while (my $change = $iter->())	{
	     say '* $change->{event}ed $change->{change}";

       Searches	the changes in the plan	returns	an iterator code reference
       with the	results. If no parameters are provided,	a list of all changes
       will be returned	from the iterator in plan order. The supported
       parameters are:

	   An array of the type	of event to search for.	Allowed	values are
	   "deploy" and

	   Limit the results to	changes	with names matching the	specified
	   regular expression.

	   Limit the changes to	those added by planners	matching the specified
	   regular expression.

	   Limit the number of changes to the specified	number.

	   Skip	the specified number of	events.

	   Return the results in the specified order, which must be a value
	   matching "/^(:?a|de)sc/i" for "ascending" or	"descending".


	 $plan->write_to($file,	$from, $to);

       Write the plan to the named file, including notes and white space from
       the original plan file. If "from" and/or	$to are	provided, the plan
       will be written only with the pragmas headers and the lines between
       those specified changes.


	 my $file_handle = $plan->open_script( $change->deploy_file );

       Opens the script	file passed to it and returns a	file handle for
       reading.	The script file	must be	encoded	in UTF-8.


	 my $plan_data = $plan->load;

       Loads the plan data. Called internally, not meant to be called
       directly, as it parses the plan file and	deploy scripts every time it's
       called. If you want the all of the changes, call	"changes()" instead.
       And if you want to load an alternate plan, use "parse()".



       Load an alternate plan by passing the complete text of the plan.	The
       text should be UTF-8 encoded. Useful for	loading	a plan from a
       different VCS branch, for example.


	 @changes = $plan->check_changes( $project, @changes );
	 @changes = $plan->check_changes( $project, { '@foo' =>	1 }, @changes );

       Checks a	list of	changes	to validate their dependencies and returns
       them. If	the second argument is a hash reference, its keys should be
       previously-seen change and tag names that can be	assumed	to be
       satisfied requirements for the succeeding changes.


	 $plan->tag( name => 'whee' );

       Tags a change in	the plan. Exits	with a fatal error if the tag already
       exists in the plan or if	a change cannot	be found to tag. The supported
       parameters are:

	   The tag name	to use.	Required.

	   The change to be tagged, specified as a supported change
	   specification as described in sqitchchanges.	Defaults to the	last
	   change in the plan.

	   A brief note	about the tag.

	   The name of the user	adding the tag to the plan. Defaults to	the
	   value of the	"" configuration variable.

	   The email address of	the user adding	the tag	to the plan. Defaults
	   to the value	of the "" configuration variable.


	 $plan->add( name => 'whatevs' );
	     name      => 'widgets',
	     requires  => [qw(foo bar)],
	     conflicts => [qw(dr_evil)],

       Adds a change to	the plan. The supported	parameters are the same	as
       those passed to the App::Sqitch::Plan::Change constructor. Exits	with a
       fatal error if the change already exists, or if the any of the
       dependencies are	unknown.


	 $plan->rework(	'whatevs' );
	 $plan->rework(	'widgets', [qw(foo bar)], [qw(dr_evil)]	);

       Reworks an existing change. Said	change must already exist in the plan
       and be tagged or	have a tag following it	or an exception	will be
       thrown. The previous occurrence of the change will have the suffix of
       the most	recent tag added to it,	and a new tag instance will be added
       to the list.

Plan File
       A plan file describes the deployment changes to be run against a
       database, and is	typically maintained using the "add" and "rework"
       commands. Its contents must be plain text encoded as UTF-8. Each	line
       of a plan file may be one of four things:

       o   A blank line. May include any amount	of white space,	which will be

       o   A Pragma

	   Begins with a "%", followed by a pragma name, optionally followed
	   by "=" and a	value. Currently, the only pragma recognized by	Sqitch
	   is "syntax-version".

       o   A change.

	   A named change change as defined in sqitchchanges. A	change may
	   then	also contain a space-delimited list of dependencies, which are
	   the names of	other changes or tags prefixed with a colon (":") for
	   required changes or with an exclamation point ("!") for conflicting

	   Changes with	a leading "-" are slated to be reverted, while changes
	   with	no character or	a leading "+" are to be	deployed.

       o   A tag.

	   A named deployment tag, generally corresponding to a	release	name.
	   Begins with a "@", followed by one or more non-blanks characters,
	   excluding "@", ":", "#", and	blanks.	The first and last characters
	   must	not be punctuation characters.

       o   A note.

	   Begins with a "#" and goes to the end of the	line. Preceding	white
	   space is ignored. May appear	on a line after	a pragma, change, or

       Here's an example of a plan file	with a single deploy change and	tag:


       There may, of course, be	any number of tags and changes.	Here's an


       Here we have four changes -- "users_table", "insert_user",
       "update_user", and "delete_user"	-- followed by two tags: "@root" and

       Most plans will have many changes and tags. Here's a longer example
       with three tagged deployment points, as well as a change	that is
       deployed	and later reverted:




       Using this plan,	to deploy to the "beta"	tag, all of the	changes	up to
       the "@root" and "@alpha"	tags must be deployed, as must changes listed
       before the "@beta" tag. To then deploy to the "@gamma" tag, the
       "dr_evil" change	must be	reverted and the "ftw" change must be
       deployed. If you	then choose to revert to "@alpha", then	the "ftw"
       change will be reverted,	the "dr_evil" change re-deployed, and the
       "@gamma"	tag removed; then "list_widgets" must be reverted and the
       associated "@beta" tag removed, then the	"widgets_table"	change must be

       Changes can only	be repeated if one or more tags	intervene. This	allows
       Sqitch to distinguish between them. An example:






       Note that the "add_widget" change is repeated after the "@beta" tag,
       and at the end. Sqitch will notice the repetition when it parses	this
       file, and allow it, because at least one	tag "@beta" appears between
       the instances of	"add_widget". When deploying, Sqitch will fetch	the
       instance	of the deploy script as	of the "@delta"	tag and	apply it as
       the first change, and then, when	it gets	to the last change, retrieve
       the current instance of the deploy script. How does it find such	files?
       The first instances files will either be	named add_widget@delta.sql or
       (soon) findable in the VCS history as of	a VCS "delta" tag.

       Here is the EBNF	Grammar	for the	plan file:

	 plan-file    =	{ <pragma> | <change-line> | <tag-line>	| <note-line> |	<blank-line> }*	;

	 blank-line   =	[ <blanks> ] <eol>;
	 note-line    =	<note> ;
	 change-line  =	<name> [ "[" { <requires> | <conflicts>	} "]" ]	( <eol>	| <note> ) ;
	 tag-line     =	<tag> (	<eol> |	<note> ) ;
	 pragma	      =	"%" [ <blanks> ] <name>	[ <blanks> ] = [ <blanks> ] <value> ( <eol> | <note> ) ;

	 tag	      =	"@" <name> ;
	 requires     =	<name> ;
	 conflicts    =	"!" <name> ;
	 name	      =	<non-punct> [ [	? non-blank and	not "@", ":", or "#" characters	? ] <non-punct>	] ;
	 non-punct    =	? non-punctuation, non-blank character ? ;
	 value	      =	? non-EOL or "#" characters ?

	 note	      =	[ <blanks> ] "#" [ <string> ] <EOL> ;
	 eol	      =	[ <blanks> ] <EOL> ;

	 blanks	      =	? blank	characters ? ;
	 string	      =	? non-EOL characters ? ;

       And written as regular expressions:

	 my $eol	  = qr/[[:blank:]]*$/
	 my $note	  = qr/(?:[[:blank:]]+)?[#].+$/;
	 my $punct	  = q{-!"#$%&'()*+,./:;<=>?@[\\]^`{|}~};
	 my $name	  = qr/[^$punct[:blank:]](?:(?:[^[:space:]:#@]+)?[^$punct[:blank:]])?/;
	 my $tag	  = qr/[@]$name/;
	 my $requires	  = qr/$name/;
	 my conflicts	  = qr/[!]$name/;
	 my $tag_line	  = qr/^$tag(?:$note|$eol)/;
	 my $change_line  = qr/^$name(?:[[](?:$requires|$conflicts)+[]])?(?:$note|$eol)/;
	 my $note_line	  = qr/^$note/;
	 my $pragma	  = qr/^][[:blank:]]*[%][[:blank:]]*$name[[:blank:]]*=[[:blank:]].+?(?:$note|$eol)$/;
	 my $blank_line	  = qr/^$eol/;
	 my $plan	  = qr/(?:$pragma|$change_line|$tag_line|$note_line|$blank_line)+/ms;

See Also
	   The Sqitch command-line client.

       David E.	Wheeler	<>

       Copyright (c) 2012-2015 iovation	Inc.

       Permission is hereby granted, free of charge, to	any person obtaining a
       copy of this software and associated documentation files	(the
       "Software"), to deal in the Software without restriction, including
       without limitation the rights to	use, copy, modify, merge, publish,
       distribute, sublicense, and/or sell copies of the Software, and to
       permit persons to whom the Software is furnished	to do so, subject to
       the following conditions:

       The above copyright notice and this permission notice shall be included
       in all copies or	substantial portions of	the Software.


perl v5.32.0			  2020-08-29		  App::Sqitch::Plan(3)

Name | Synopsis | Description | Interface | Plan File | See Also | Author | License

Want to link to this manual page? Use this URL:

home | help