Equivalent to git difftool -y with libgit2sharp? - libgit2sharp

I am planning to replace the usage of git.exe from windows path by libgit2sharp for my plugin GitDiffMargin, A Visual Studio 2012 extension to display Git Diff on the margin of the current file. - https://github.com/laurentkempe/GitDiffMargin
I would like to know if there is an equivalent in libgit2sharp to start the external difftool using git difftool -y filename ?

I don't think it should be the responsibility of LibGit2Sharp to launch an external process. LibGit2Sharp goal is to provide a way to manipulate a git repository easily.
It means you can use it to:
Get the diff between files in the workdir and the previous version (in the index). To do that you can use the Repository.Diff.Compare(IEnumerable<string> paths, bool includeUntracked, ExplicitPathsOptions explicitPathsOptions) overload, which returns a TreeChanges object. From there, you can get a TreeEntryChanges object through the indexer of the treeChanges, which corresponds to the changes of a given file (use the .Patch property to get the actual content of the patch).
Get the configured diff tool by using the Repository.Config namespace (e.g.: repo.Config.Get<string>("diff.tool").Value, although you should also check if the value returned by the Get() method is null in case no diff tool has been configured by the user). That way, you can launch the diff tool by yourself.
Additional resources (v0.11.0):
Diff workdir to index tests
An example showing how to use the TreeChanges object
Configuration fixture, pretty self-explanatory
Note: it seems that at some point, you will need to know if a line has changed or not. I don't think there is an easy way to do that right now (apart from parsing the patch content manually). However, opening an issue on the LibGit2Sharp issue tracker might trigger some discussion around that (feel free to weigh in what kind of API you would like to have to do that!).
Edit: Before launching the external diff tool, you will need to copy the content of the file which is in the index in a temporary folder. You can lookup the blob of a file in the index by doing something like:
var indexEntry = repo.Index[fileName];
var blob = repo.Lookup(indexEntry.Id);
However... no filters are currently applied when you get the blob content, so the comparison is likely to produce false positives due to crlf differences.
There is currently an issue opened on libgit2 in order to propose an API to allow applying filters.

Related

Are absolute paths safe to use in Bazel?

I am experimenting with Bazel to be added along with an old, make/shell based build system. I can easily make shell commands which returns an absolute path to some tool or library build by the old build system as early prerequisites. These commands I can use in a genrule(), which copies the needed files (like headers and libs) into Bazel proper to be exposed in form of a cc_library().
I found out that genrule() does not detect a dependency if the command uses a file with absolute path - it is not caught by the sandbox. In a way I am (ab)using that behavior.
It is it safe? Will some future update of Bazel refuse access to files based on absolute path in that way in a command in genrule?
Most of Bazel's sandboxes allow access to most paths outside of the source tree by default. Details depend on which sandbox implementation you're using. The docker sandbox, for example, allows access to all those paths inside of a docker image. It's kind of hard to make promises about future Bazel versions, but I think it's unlikely that a sandbox will prevent accessing /bin/bash (for example), which means other absolute paths will probably continue to work too.
--sandbox_block_path can be used to explicitly block a path if you want.
If you always have the files available on every machine you build on, your setup should work. Keep in mind that Bazel will not recognize when the contents of those files change, so you can easily get stale results in various caches. You can avoid that by ensuring the external paths change whenever their contents do.
new_local_repository might be a better fit to avoid those problems, if you know the paths ahead of time.
If you don't know the paths ahead of time, you can write a custom repository rule which runs arbitrary commands via repository_ctx.execute to retrieve the paths and them symlinks them in with repository_ctx.symlink.
Tensorflow's third_party/sycl/sycl_configure.bzl has an example of doing something similar (you would do something other than looking at environment variables like find_computecpp_root does, and you might symlink entire directories instead of all the files in them):
def _symlink_dir(repository_ctx, src_dir, dest_dir):
"""Symlinks all the files in a directory.
Args:
repository_ctx: The repository context.
src_dir: The source directory.
dest_dir: The destination directory to create the symlinks in.
"""
files = repository_ctx.path(src_dir).readdir()
for src_file in files:
repository_ctx.symlink(src_file, dest_dir + "/" + src_file.basename)
def find_computecpp_root(repository_ctx):
"""Find ComputeCpp compiler."""
sycl_name = ""
if _COMPUTECPP_TOOLKIT_PATH in repository_ctx.os.environ:
sycl_name = repository_ctx.os.environ[_COMPUTECPP_TOOLKIT_PATH].strip()
if sycl_name.startswith("/"):
return sycl_name
fail("Cannot find SYCL compiler, please correct your path")
def _sycl_autoconf_imp(repository_ctx):
<snip>
computecpp_root = find_computecpp_root(repository_ctx)
<snip>
_symlink_dir(repository_ctx, computecpp_root + "/lib", "sycl/lib")
_symlink_dir(repository_ctx, computecpp_root + "/include", "sycl/include")
_symlink_dir(repository_ctx, computecpp_root + "/bin", "sycl/bin")

Where to get list of known repositories like #bazel_tools, #rules_jvm_external etc?

Sometimes I see extensions loading from the internet or built-in ones.
Canonical example:
load("#bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
However, I cannot distinguish local repo and known repo by looking at the load expression.
How can I check the source (location) of any repo which I see in my WORKSPACE/BUILD files?
If the Bazel label is sufficient as a source, you might try fetching repo roots with BUILD files with bazel query 'buildfiles(//...)'.
Otherwise, you could run bazel clean --expunge and run a build with --experimental_execution_log_file=<FILENAME>. This creates a protobuf based log of the actions by Bazel. In there, all internet repos are downloaded anew because of clean --expunge.
Check https://github.com/bazelbuild/bazel/tree/master/src/tools/execlog for a parser.
It is super inconvenient that this information is not available another way - afaik. I really hope someone swings by and corrects me, but this way you at least know the available sources you can correlate.
I'm new to Bazel, but as far as I understand:
Copy the name of the repo. E.g. io_bazel_rules_docker
Search it through the codebase
Look at how it's being loaded
E.g. if you see
http_archive(
name = "io_bazel_rules_docker",
...
)
http_file(
name = "io_bazel_rules_docker",
...
)
And you can conclude where it's coming from.
bazel query --output=build //external:repo_name works just fine.

Determine if files are part of any package

Given I have a list of files, e.g foo/src/main.cpp, foo/src/bar.cpp, foo/README.md is it possible to determine which of those files are part of a bazel package?
In my example, the output would e.g. be foo/src/main.cpp, foo/src/bar.cpp since the README.md would not be part of the build.
One way to do this would be to call bazel query on each file and see if it results in an output, but that is quite inefficient and so I was wondering if there is an easier way.
Background: I am trying to determine if a changes in a set of files have an impact on a target, and I want to use bazel query somepath(//some/target, set($FILES)) for that, but this will fail if any of the files in $FILES is not part of a BUILD file.
How about flipping it around and querying for all the source files of the target with:
bazel query 'kind("source file", deps(//some:target))'
and then checking if the result has any of the files in the set

Skylark - can a rule access the attributes of another rule from its label?

This question piggybacks this github issue. However, I have ran into this issue in one other context.
Context
Within Bazel, there are two repository rules, maven_jar and maven_server.
maven_jar(name, artifact, repository, server, sha1)
maven_server(name, repository, settings)
The maven_jar rule's server attribute is a label pointing to some maven_server target.
Currently, whenever the server attribute is provided, the maven_jar rule errors out.
What I would like to accomplish
Within maven_jar's implementation function, I would like to access the maven_server's attributes. Specifically, I would like to do something along the lines of:
def _impl(rtx):
settings_attr = rtx.attr.server.getSettings()
# alternatively
settings_attr = rtx.attr.server.getAttributes().settings
Is this behavior supported? If not, any way I can approximate it?
The server attribute is a label, so I'm not sure if one can obtain these values using its providers/aspects.
Repository rules are macros, so they do not have providers the same way "normal" rules do. Thus, if you specify a label attribute, it basically has to be a source file.
As settings.xml isn't supposed to be project-specific, I think it mgiht make more sense for maven_jar to use the users/system's settings.xml, as described in the Maven docs:
There are two locations where a settings.xml file may live:
The Maven install: ${maven.home}/conf/settings.xml
A user’s install: ${user.home}/.m2/settings.xml
The former settings.xml are also called
global settings, the latter settings.xml are referred to as user
settings. If both files exists, their contents gets merged, with the
user-specific settings.xml being dominant.

Is it possible to compare files using Plastic SCM Command Line 'cm diff' function?

I'd like to compare two files at particular changesets to see if they are identical or not.
Something like:
>> cm diff rev:Folder\MyFile.py#cs:5 rev:Folder\MyFile.py#cs:10
<< True
I'm getting an error (can't find revision of file I specify) and I think I might not be using diff as it's intended. I've worked around my confusion by using getfile on the particular file and changesets I'm comparing and using a python library file compare.
Thanks.
The Plastic SCM default diff tool will open a GUI showing you the file differences.
But you can manually configure a different one (eg. diff.exe) manually editing the "/home/user/.plastic/client.conf" or using the Plastic SCM GUI:
<DiffToolData>
<FileType>enTextFile</FileType>
<FileExtensions>*</FileExtensions>
<Tools>
<string>diff.exe #sourcefile #destinationfile</string>
</Tools>
</DiffToolData>
This way, you can run diffs through the command line and based on the output, determine if the files are identical or not.
You can use cm patch command
reference : https://blog.plasticscm.com/2018/11/unified-diff-of-branch.html

Resources