-
Notifications
You must be signed in to change notification settings - Fork 955
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
introducing modern conan.tool.scm.Git helper #10594
Changes from 17 commits
ae66be8
1bfa516
d811e17
ccca294
04e356d
9c0e46b
6af4427
eeb123b
db807ec
d77c1a6
679ec4b
683700a
9d3e456
4a63607
da035a3
ea8bd95
42a7a00
e6ba52a
a4aa3a9
a092439
658e7c3
29fb041
ff7e5e5
b01610d
b5cd928
6209836
13e2a71
ad8af04
3543fcc
64d5c1d
604ba15
b6971ba
827b39a
c6e4317
0aba37a
45741ba
2cf53db
b710317
cadb399
6dde3ca
18491a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from conan.tools.scm.git import Git |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import os | ||
|
||
from conan.tools.files import chdir | ||
from conans.errors import ConanException | ||
from conans.util.files import mkdir | ||
from conans.util.runners import check_output_runner | ||
|
||
|
||
class Git(object): | ||
def __init__(self, conanfile, folder): | ||
self._conanfile = conanfile | ||
self.folder = folder | ||
|
||
def _run(self, cmd): | ||
with chdir(self._conanfile, self.folder): | ||
return check_output_runner("git {}".format(cmd)).strip() | ||
|
||
def get_commit(self): | ||
try: | ||
# commit = self._run("rev-parse HEAD") For the whole repo | ||
# This rev-list knows to capture the last commit for the folder | ||
commit = self._run('rev-list HEAD -n 1 -- "{}"'.format(self.folder)) | ||
return commit | ||
except Exception as e: | ||
raise ConanException("Unable to get git commit in '%s': %s" % (self.folder, str(e))) | ||
|
||
def get_remote_url(self, remote="origin"): | ||
remotes = self._run("remote -v") | ||
for r in remotes.splitlines(): | ||
name, url = r.split(maxsplit=1) | ||
if name == remote: | ||
url, _ = url.rsplit(None, 1) | ||
if os.path.exists(url): # Windows local directory | ||
url = url.replace("\\", "/") | ||
return url | ||
|
||
def commit_in_remote(self, commit, remote="origin", branch="master"): | ||
if not remote or not branch: | ||
return False | ||
try: | ||
branches = self._run("branch -r --contains {}".format(commit)) | ||
return "{}/{}".format(remote, branch) in branches | ||
except Exception as e: | ||
raise ConanException("Unable to check remote commit in '%s': %s" % (self.folder, str(e))) | ||
|
||
def is_dirty(self): | ||
status = self._run("status -s").strip() | ||
return bool(status) | ||
|
||
def get_url_commit(self, remote="origin", branch="master"): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should change this default to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can avoid using the branch and just use the commit hash? Do we need the branch name? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, need to find a better name. In any case, the branch needs to be worked out. It shouldn't be necessary, and indeed is very problematic for user flows like branching, PRs, in which the branch will not be "main" or "master". So the commit should be looked for directly in the remote without a branch hint, I'll investigate if this is possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have changed the name to |
||
dirty = self.is_dirty() | ||
if dirty: | ||
raise ConanException("Repo is dirty, cannot capture url and commit: " | ||
"{}".format(self.folder)) | ||
commit = self.get_commit() | ||
url = self.get_remote_url(remote=remote) | ||
in_remote = self.commit_in_remote(commit, remote=remote, branch=branch) | ||
if in_remote: | ||
return url, commit | ||
# TODO: Once we know how to pass [conf] to export, enable this | ||
# conf_name = "tools.scm:local" | ||
# allow_local = self._conanfile.conf[conf_name] | ||
# if not allow_local: | ||
# raise ConanException("Current commit {} doesn't exist in remote {}\n" | ||
# "use '-c {}=1' to allow it".format(commit, remote, conf_name)) | ||
|
||
self._conanfile.output.warn("Current commit {} doesn't exist in remote {}\n" | ||
"This revision will not be buildable in other " | ||
"computer".format(commit, remote)) | ||
return self.get_repo_root(), commit | ||
|
||
def get_repo_root(self): | ||
folder = self._run("rev-parse --show-toplevel") | ||
return folder.replace("\\", "/") | ||
|
||
def clone(self, url, target=""): | ||
if os.path.exists(url): | ||
url = url.replace("\\", "/") # Windows local directory | ||
mkdir(self.folder) | ||
self._conanfile.output.info("Cloning git repo") | ||
self._run('clone "{}" {}'.format(url, target)) | ||
|
||
def checkout(self, commit): | ||
self._conanfile.output.info("Checkout: {}".format(commit)) | ||
self._run('checkout {}'.format(commit)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name to be improved. Suggestions welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a generic
move_folder_contents(dst_folder, folder, clean_first=True)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe we can split the operation in two, one for removing all folders but the one we want and other for moving the folder... or
move_folder_contents(dst_folder, folder, clean_first=True)
is more explicit, I'm ok with that too, maybeclean_other
instead ofclean_first
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am annotating it to NOT document, so we can think about file methods in a more broad perspective, this PR is focused on the Git integration for sources, this is a very minor detail, just to prove it is possible to implement the mono-repo approach