How do I write my hgrc so that Mercurial detects my hooks? - mercurial

've written two functions in a file commit_hooks.py that I want to run before any commit is made persistent, but I can't figure out how to write my hgrc to detect them.
The function headers are:
def precommit_bad_merge(ui, repo, parent1=None, parent2=None, **kwargs):
...
def precommit_bad_branching(ui, repo, **kwargs):
...
I've tried using this "guide", but the documentation is too "man pagey" for me. The following is an outcast which doesn't work.
[hooks]
precommit = ..\..\mno2\commit_hooks.py
Update!
Rewriting the hook line to:
precommit = D:\environments\next\mno2\commit_hooks.py
make Mercurial detect the precommit hook, but it always exits with status 1 for some reason.

Set up your [hooks] section like this:
[hooks]
precommit.foo = python:D:\environments\next\mno2\commit_hooks.py:precommit_bad_merge
precommit.bar = python:D:\environments\next\mno2\commit_hooks.py:precommit_bad_branching
The syntax for the precommit line that you used is for external hooks, so it was treating your python file as a self-contained script (which I'm assuming it's not since you're using the function signatures for in-process hooks).
You may need to have the python executable in your path (I do).
For more information, see the definitive guide's section on in-process hooks; there's some useful information hidden in the comments.

The "man pagey" documentation has a section on python hook syntax:
The syntax for Python hooks is as
follows:
hookname = python:modulename.submodule.callable
hookname = python:/path/to/python/module.py:callable
Python hooks are run within the
Mercurial process. Each hook is called
with at least three keyword arguments:
a ui object (keyword ui), a repository
object (keyword repo), and a hooktype
keyword that tells what kind of hook
is used. Arguments listed as
environment variables above are passed
as keyword arguments, with no HG_
prefix, and names in lower case.
If a Python hook returns a "true"
value or raises an exception, this is
treated as a failure.

Related

Correct way to pass runtime configuration to elixir processes

I'm trying to deploy an app to production and getting a little confused by environment and application variables and what is happening at compile time vs runtime.
In my app, I have a genserver process that requires a token to operate. So I use config/releases.exs to set the token variable at runtime:
# config/releases.exs
import Config
config :my_app, :my_token, System.fetch_env!("MY_TOKEN")
Then I have a bit of code that looks a bit like this:
defmodule MyApp.SomeService do
use SomeBehaviour, token: Application.get_env(:my_app, :my_token),
other_config: :stuff
...
end
In production the genserver process (which does some http stuff) gives me 403 errors suggesting the token isn't there. So can I clarify, is the use keyword getting evaluated at compile time (in which case the application environment doest exist yet)?
If so, what is the correct way of getting runtime environment variables in to a service like this. Is it more correct to define the config in application.ex when starting the process? eg
children = [
{MyApp.SomeService, [
token: Application.get_env(:my_app, :my_token),
other_config: :stuff
]}
...
]
Supervisor.start_link(children, opts)
I may have answered my own questions here, but would be helpful to get someone who knows what they're doing confirm and point me in the right way. Thanks
elixir has two stages: compilation and runtime, both written in Elixir itself. To clearly understand what happens when one should figure out, that everything is macro and Elixir, during compilation stage, expands these macros until everything is expanded. That AST comes to runtime.
In your example, use SomeBehaviour, foo: :bar is implicitly calling SomeBehaviour.__using__/1 macro. To expand the AST, it requires the argument (keyword list) to be expanded as well. Hence, Application.get_env(:my_app, :my_token) call happens in compile time.
There are many possibilities to move it to runtime. If you are the owner of SomeBehaviour, make it accept the pair {:my_app, :my_token} and call Application.get_env/2 somewhere from inside it.
Or, as you suggested, pass it as a parameter to children; this code belongs to function body, meaning it won’t be attempted to expand during compilation stage, but would rather be passed as AST to the resulting BEAM to be executed in runtime.

How to pass options to UglifyJS through html-minifier on Windows command line?

HTMLMinifier (html-minifier) (3.5.14) for Node.js (v8.11.1), installed with npm install html-minifier -g, can be run via command line (Windows CMD), e.g. html-minifier --help produces the usage info (excerpts):
Usage: html-minifier [options] [files...]
Options:
-V, --version output the version number
...
--minify-js [value] Minify Javascript in script elements and on* attributes (uses uglify-js)
...
-c --config-file <file> Use config file
--input-dir <dir> Specify an input directory
--output-dir <dir> Specify an output directory
--file-ext <text> Specify an extension to be read, ex: html
-h, --help output usage information
The option --minify-js [value] relies on UglifyJS to "compress" the JavaScript embedded inside the HTML file(s) passed to html-minifier. UglifyJS can remove console.log() function calls (Can uglify-js remove the console.log statements?) from the JavaScript, by enabling the drop_console option (also see pure_funcs).
But --minify-js drop_console=true does not have an effect, nor does something like "uglify:{options:{compress:{drop_console:true}}}" or "compress:{pure_funcs:['console.log']}".
How can such an option be set, ideally via the html-minifier command line (alternatively by config-file, though it just sets "minifyJS": true)?
I was very close.
I started digging through the code (installed in %appdata%\npm\node_modules\html-minifier) to see what happens with the options provided, i.e. adding debug output with console.log(xyz); (using an actual debugger probably would be a better idea).
So, here's my "trace":
option: https://github.com/kangax/html-minifier/blob/gh-pages/cli.js#L118
option handling: https://github.com/kangax/html-minifier/blob/gh-pages/cli.js#L144
argument parsing using [commander][2]
createOptions() https://github.com/kangax/html-minifier/blob/gh-pages/cli.js#L197
options then contains e.g. minifyJS: 'compress:{pure_funcs:[\'console.log\']}',
passed on to minify() https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L806 which immediately runs
processOptions() https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L616
where finally in line https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L667 options.minifyJS is handled, before it's run as var result = UglifyJS.minify(code, minifyJS); in https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L680.
But there our option string compress:{pure_funcs:['console.log']} gets cleaned because it's not yet an object, resulting in {}.
Or, in a different trial with a different string you may encounter the error Could not parse JSON value '{compress:{pure_funcs:'console.log']}}'
At least it gets that far! But why doesn't it work?
First, it's a good time to revisit the JSON spec: https://www.json.org/index.html
Second, see if the string could be parsed as valid JSON, e.g. with the JSON.parse() demo at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
Third, figure out how to get that string through the CMD as argument (escaping the double quotes).
Finally, make sure the data structure to configure UgliFyJS is correct. That's quite easy, since it's documented: https://github.com/mishoo/UglifyJS2#minify-options-structure
And behold, simply escaping the double quotes with a backslash works for me:
html-minfier ... --minify-js {\"compress\":{\"pure_funcs\":[\"console.log\"]}} ...
and it properly shows up in the options as
...
{ compress:
{ pure_funcs: [ 'console.log' ],
...
For ex. curl can read config from a file, like proxies, etc...
Many programs do so. git, maven, gradle.... No matter how and where you call them, they look for the config you or the system provides: first from the current directory, then from the user home and then the system /etc/...
If no batteries included with these node packages, they can only be used on separate html and js files.

To undefine in .bbappend shell function defined in .bb file

One .inc file included in some image-.bb file defines shell function for Bitbake task.
Let's concentrate here merely on this shell function, asigned Bitbake task is out of scope.
I wonder how to undefine this shell function in .bbappend file (other layer).
unset -f <shell-function-name>
is not working
ERROR: ParseError at .......-image.bbappend:89: unparsed line: 'unset -f do_thisandthat'
Does it need be said Bitbake explicitely "unset -f < shell-function-name>" is a shell script?
Me consulted for this question Bitbake Manual and Yocto Project Reference Manual with outcome of zero findings.
There is no direct API for it however you can do something like:
python () {
d.delVar("shell function name")
}
which will delete the shell function since functions are simply variables.
Just deleting a function may well cause other problems but that does answer your specific question.
This is an 'anonymous python' fragment and will be executed by bitbake at the end of parsing a recipe (or bbappend to a recipe).

How to show hook output in Tortoise Hg log window?

I need simple hook for mercurial that checks commit comment using pattern. Here is my hook:
#!/usr/bin/env python
#
# save as .hg/check_whitespace.py and make executable
import re
def check_comment(comment):
#
print 'Checking comment...'
pattern = '^((Issue \d+:)|(No Issue:)).+'
if re.match(pattern, comment, flags=re.IGNORECASE):
return 1
else:
print >> sys.stderr, 'Comment does not match pattern. You must start it with "Issue 12323:" or "No Issue:"'
return 0
if __name__ == '__main__':
import os, sys
comment=os.popen('hg tip --template "{desc}"').read()
if not check_comment(comment):
sys.exit(1)
sys.exit(0)
It works. It even shows error message 'Comment does not match pattern. You must start it with "Issue 12323:" or "No Issue:"' when I commit from console. But when I trying to commit from Tortoise Hg Workbench, only system message is shown: abort: pretxncommit.check_comment hook exited with status 1.
I need to inform user what is wrong. Is there any way to force Tortoise Hg to show output from hook?
I got it to work by making it an in-process hook rather than an external hook. In-process hooks are defined quite differently, however.
First, the python file needs only a single function that will be called by the name in the hook definition. The hook function is passed ui, repo, and hooktype objects. It is also passed additional objects based on the type of hook. For pretrxncommit, it is passed node, parent1, and parent2, but you're only interested in node, so the rest are gathered in kwargs. The ui object is used to give the status and error messages.
Contents of check_comment.py:
#!/usr/bin/env python
import re
def check_comment(ui, repo, hooktype, node=None, **kwargs):
ui.status('Checking comment...\n')
comment = repo[node].description()
pattern = '^((Issue \d+:)|(No Issue:)).+'
if not re.match(pattern, comment, flags=re.IGNORECASE):
ui.warn('Comment does not match pattern. You must start it with "Issue 12323:" or "No Issue:"\n')
return True
In the hgrc, the hook would be defined with python:/path/to/file.py:function_name, like this:
[hooks]
pretxncommit.check_comment = python:/path/to/check_comment.py:check_comment
The .suffix_name on pretxncommit is to avoid overriding any globally defined hook, especially if this is defined in the repository's hgrc rather than the global one. Suffixes are how one allows multiple responses to the same hook.
In case the hook runs on a repository that is served via e.g. hgserve:
I use this small Python function in a pretxnchangegroup script to show the same output
in the server log
in the TortoiseHg workbench Log pan or the cmd line
:
def log(ui, string):
print(string) # will show up as "remote:" on the client
ui.status("{0}\n".format(string)) # will show up in the same hg process: hgserve ; append newline
return

What are the hook parameters passed to external hook program/script?

The title says it: I am looking for the variable names (HG_*) so I can make use of them in my hook script..
Oben has your best answer, but for specific cases or poorly documented options you can easily test specific hooks using a hook that just prints variables:
hg --config hooks.pre-commit="export| grep HG_" commit
Where pre-commit can be any hook you want to test and commit can be any command you want to test.
For example that one showed:
export HG_ARGS='commit'
export HG_OPTS='{'"'"'exclude'"'"': [], '"'"'message'"'"': '"''"', '"'"'addremove'"'"': None, '"'"'include'"'"': [], '"'"'close_branch'"'"': None, '"'"'user'"'"': '"''"', '"'"'date'"'"': '"''"', '"'"'logfile'"'"': '"''"', '"'"'mq'"'"': None}'
export HG_PATS='[]'
The hooks section in the hgrc manpage lists all defined hooks, including the environment variables available for each hook.