## versiontool.pkg
## Author: Matthias Blume (blume@tti-c.org)
# A CM tool for automatically generating file version.pkg
# from a template, incorporating current version and release.
### "The good Christian should beware of mathematicians
### and all those who make empty prophecies. The danger
### already exists that mathematicians have made a covenant
### with the devil to darken the spirit and confine man in
### the bonds of Hell."
###
### -- St. Augustine (354-430)
stipulate
package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkgherein
package version_tool {
with
bump_release
=
REF (null_or::not_null (winix__premicrothread::process::get_env "VERSIONTOOL_BUMP_RELEASE"));
fun get_version file
=
{ s = fil::open_for_read file;
#
case (fil::read_line s)
#
THE l
=>
{ fil::close_input s;
#
fl = string::tokens
(\\ c = char::is_space c or c == '.')
l;
map
(\\ f = the_else (int::from_string f, 0))
fl;
};
NULL => [0, 0];
esac;
}
except
_ = [0, 0];
fun get_release file
=
{ s = fil::open_for_read file;
#
case (fil::read_line s)
#
THE l => { fil::close_input s; int::from_string l; };
NULL => { fil::close_input s; NULL; };
esac;
}
except
_ = NULL;
fun put_release (file, r)
=
{ s = fil::open file;
#
fil::write (s, int::to_string r + "\n");
fil::close s;
};
fun bump_release_fn (file, r)
=
if *bump_release
then
put_release (file, r + 1);
fi;
fun gen { template, target, vfile, release }
=
{ version = get_version vfile;
#
version' = case release
NULL => version;
THE r => version @ [r];
esac;
vstring = string::join ", " (map int::to_string version');
ss = fil::open_for_read template;
ts = fil::open target;
fun loop ()
=
case (fil::read_one ss)
#
THE '%'
=>
case (fil::read_one ss)
#
THE 'V' => { fil::write (ts, vstring);
loop ();
};
THE 'F' => { fil::write (ts, winix__premicrothread::path::file target);
fil::write (ts, " generated from");
loop ();
};
THE c => { fil::write_one (ts, c);
loop ();
};
NULL => fil::write_one (ts, '%');
esac;
THE c => { fil::write_one (ts, c);
loop ();
};
NULL => ();
esac;
loop ();
fil::close_input ss;
fil::close ts;
};
tool = "versiontool";
ilk = "version";
kw_target = "target";
kw_versionfile = "versionfile";
kw_releasefile = "releasefile";
keywords = [kw_target, kw_versionfile, kw_releasefile];
fun versiontoolrule
{ spec: tools::Spec,
native2pathmaker,
context: tools::Rulecontext,
default_ilk_of,
sysinfo
}
:
tools::Partial_Expansion
=
{ fun dogen (targetpp, versionfilepp, releasefilepp) ()
=
{ templatep = tools::srcpath (spec.make_path ());
targetp = tools::srcpath targetpp;
target = tools::native_spec targetp;
template = tools::native_spec templatep;
vfile = tools::native_pre_spec versionfilepp;
rfile = tools::native_pre_spec releasefilepp;
release = get_release rfile;
fun newer_than_target f
=
tools::outdated tool ([target], f);
if list::exists newer_than_target [template, vfile, rfile]
then
gen { template, target, vfile, release };
fi;
bump_release_fn (rfile, the_else (release, -1));
( { source_files => [ (targetp, { share => sharing_mode::DONT_CARE,
setup => (NULL, NULL),
split => NULL,
noguid => FALSE,
local => FALSE,
controllers => []
}
)
],
makelib_files => [],
sources => [ (templatep, { ilk,
derived => spec.derived }
)
]
},
[]
);
};
fun complain l
=
raise exception tools::TOOL_ERROR { tool, msg => cat l };
case spec.opts
NULL
=>
complain ["missing parameters"];
THE to
=>
{ my { matches, restoptions }
=
tools::parse_options { tool, keywords, options => to };
fun match kw
=
case (matches kw)
NULL
=>
complain ["missing parameter \"", kw, "\""];
THE [tools::STRING { make_path, ... } ]
=>
make_path ();
_ =>
complain ["invalid parameter \"", kw, "\""];
esac;
context (dogen ( match kw_target,
match kw_versionfile,
match kw_releasefile
)
);
};
esac;
};
do
bump_release = bump_release;
my _ =
tools::note_ilk (ilk, versiontoolrule);
end;
};
end;