How to show hook output in Tortoise Hg log window? - mercurial

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

Related

Run cython code when extension module gets garbage collected

Is there a way to register a function within an Cython extenstion module such that this function is called when the Python garbage collector destroys the module object ?
Something like
def __dealloc__(...)
on module level ?
I'm not sure there is an explicit/official way to achieve that. However, you could add a global variable which will be destroyed, when the cython module is deallocated:
# foo.pyx:
class Observer:
def __init__(self):
print("module initialized")
def __del__(self):
print ("module deleted")
_o=Observer()
However, cythonizing it via cythonize foo.pyx -i will not lead to the desired effect:
[$] python -c `import foo`
module initialized
there is no "module deleted" printed to the console!
The problem: one cannot reload a cython-extension anyway (for example via importlib.reload()), so it gets only deallocated when the Python interpreter is shut down. But then there is no need to deallocate the resources ...
Cython keeps all global Python-variables in a global C-variable which is called static PyObject *__pyx_d; in the cythonized C-source; this is just a Python-dictionary. However, because there is a reference to the global _o in this not destroyed dictionary, the reference count of _o will never become 0 an thus the object doesn't get destroyed.
By setting generate_cleanup_code=True one can force Cython to generate a clean-up function which will be put into the m_free-slot of the PyModuleDef definition struct. For example with the following setup-file:
from distutils.core import setup
from Cython.Build import cythonize
from Cython.Compiler import Options
Options.generate_cleanup_code = True # this is important!
setup(
name = "foo",
ext_modules = cythonize("foo.pyx"),
)
And now after python setup.py build_ext -i:
[$] python -c "import foo"
module initialized
module deleted
it works as expected.
Because there is no reload for Cython-extensions, "module deleted" will be only seen when module_dealloc is called.
However, when the first listing were pure-Python, we would also see module deleted if importlib.reload(foo) were called. In this case "module_dealloc" isn't used, but all references to global _o would be cleared and object would be destroyed.
Depending on what one want, it might be either the expected or unexpected behavior.

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.

Where does jruby log to?

I see a lot of config options like jit.logging=true, and I want to watch out for things like when the jvm gives CodeCache is full. Compiler has been disabled messages, where does jruby log this stuff? Better yet, how can I tell it which file to log to? Is it just STDOUT and STDERR?
By setting JRuby properties that affects JIT Runtime Properties ( such as: jruby.jit.logging, jruby.jit.logging, jruby.jit.logging ) you get log to standard error (commonly abbreviated stderr)
You could tell which file to log to by redirecting stderr to a specific file; for example:
jruby -J-Djruby.jit.logging=true myscript.rb 2> myfile.log
beware, however, myfile.log receives even other stderr outputs; i.e if myscript.rb
executes statements such as:
$stderr.puts "print this in stderr"
you will see "print this in stderr" in myfile.log

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.

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

'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.