$ gclient sync
and end up with a clone of whatever solution (project) was specified in the .gclient file.
The next thing I'd like to is to add some dependencies. As you recall, we told gclient config to use git dependencies, which means we need to come up with a .DEPS.git file that specifies the dependencies of the project. I believe that you can use any filename you want, as long as .gclient file reflects that, but don't quote me on that.
So far, here's what I have:
$ ls -1a . .. .gclient $ cat .gclient solutions = [ { "name" : "my_project", "url" : "ssh://example.com/repos/my_project.git", "deps_file" : ".DEPS.git", "managed" : True, "custom_deps" : { }, "safesync_url": "", }, ] cache_dir = None $ gclient sync Syncing projects: 100% (1/1), done. $ ls -a . .. .gclient .gclient_entries my_project
There's a new file .gclient_entries, and my project clone (the same thing I would get if I did a git clone ssh://example.com/repos/my_project.git)
For completeness,
$ cat .gclient_entries entries = { 'my_project': 'ssh://example.com/repos/my_project.git', }
That seems to be a simple map of project name (possibly directory) to the git url of the project. I'll just leave that alone.
Now, I'd like to add a dependency to this project. I will probably have a lot of dependencies, but let's just add googletest.
It has its own repository and uses subversion as far as I can tell. Since I prefer to have all of my code and dependencies on one host, I actually went ahead and cloned googletest, then created a git repo on my host (what I refer to as example.com here), and committed it there. So, googletest is available for me form ssh://example.com/repos/external/googletest.git. Note that in the future, it might be worth it to experiment with adding dependency straight from the source, but for now I want to be able to keep track of everything.
Now, to add a .DEPS.git to the main project. Ha! I have no idea what it supposed to look like. Since I know Chromium has a bunch of dependencies, that's probably a good spot to start digging. Conveniently, Chromium has a very useful code search tool that allows us to take a look at the full source code without needing to clone a local copy: cs.chromium.org. Searching for .DEPS.git gets me pretty quickly to this file.
It looks like it has the following structure:
vars = { ... } deps = { ... } deps_os = { ... } include_rules = { ... } skip_child_includes = { ... } hooks = { ... }
It also supports comments like most good files. Now, since gclient didn't mind when I didn't have this file, I'm hoping that it doesn't mind if I omit some of the sections. In particular, since I'm only trying to get one dependency to clone, I'm not going to put in anything after deps (ie deps_os, include_rules, etc).
Also, since I want this to be maintainable, I'm going to define convenient vars and use them in deps. Here's my first attempt:
vars = { # Common settings. "base_url" : "ssh://example.com/repos", # Specify dependency package |package| as package_destination, # package_url, and package_revision tuples. Then, ensure to # add the dependency in deps using the variables. # Google test "googletest_destination" : "third_party/googletest", "googletest_url" : "/external/googletest.git", "googletest_revision" : "2a2740e0ce24acaae88fb1c7b1edf5a2289d3b1c", } deps = { # Google test Var("googletest_destination") : Var("base_url") + Var("googletest_url") + "@" + Var("googletest_revision") }
Most of the fields are self explanatory. Googletest_revision refers to the git hash of the latest (and in my case only) git checking. You can get this via git log if you clone the repo separately.
Let's see what sync gets us:
$ gclient sync Syncing projects: 100% (2/2), done.
That seems to have worked, 2/2 is a good thing, but...
$ ls my_project/ README
my_project only has README that I added to it independently. Let's see what happened. Asking gclient to print more information gets us the following:
$ gclient sync --verbose solutions = [ { "name" : "my_project", "url" : "ssh://example.com/repos/my_project.git", "deps_file" : ".DEPS.git", "managed" : True, "custom_deps" : { }, "safesync_url": "", }, ] cache_dir = None my_project (Elapsed: 0:00:01) ---------------------------------------- [0:00:00] Started. _____ my_project at refs/remotes/origin/master [0:00:01] Fetching origin Checked out revision ec01ec9b2387175083549cb155d5aa00a6311ed0 [0:00:01] Finished. ---------------------------------------- third_party/googletest (Elapsed: 0:00:00) ---------------------------------------- [0:00:01] Started. _____ third_party/googletest at 2a2740e0ce24acaae88fb1c7b1edf5a2289d3b1c [0:00:01] Up-to-date; skipping checkout. Checked out revision 2a2740e0ce24acaae88fb1c7b1edf5a2289d3b1c [0:00:01] Finished. ----------------------------------------
Hmm everything up to date. Ah! The problem is that it seems to have checked out googletest relative to the .gclient file, not relative to the project:
$ ls -1 my_project third_party
I guess that's useful in some scenarios, but I would really prefer to keep my third_party libs inside my_project directory. That's easy enough to fix. Here's an updated .DEPS.git:
vars = { # Common settings. "base_url" : "ssh://example.com/repos", "project_directory" : "my_project", # Specify dependency package |package| as package_destination, # package_url, and package_revision tuples. Then, ensure to # add the dependency in deps using the variables. # Google test "googletest_destination" : "third_party/googletest", "googletest_url" : "/external/googletest.git", "googletest_revision" : "2a2740e0ce24acaae88fb1c7b1edf5a2289d3b1c", } deps = { # Google test Var("project_directory") + "/" + Var("googletest_destination") : Var("base_url") + Var("googletest_url") + "@" + Var("googletest_revision") }
I added a project_directory variable and modified deps to use that as the leading directory before googletest_destination. Let's see if that does it:
$ gclient sync Syncing projects: 100% (2/2), done. WARNING: 'third_party/googletest' is no longer part of this client. It is recommended that you manually remove it. $ ls -1 my_project README third_party
That seems to have worked with a useful message reminding me that third_party/googletest (not my_project/third_party/googletest) was removed, so I should clean that up.
Running gclient sync again does not produce the message again. This means that gclient records what dependencies I had on the last run, and warns me if they are no longer in the new .DEPS.git (protip: it's in .gclient_entries). Got it. I'll remove third_party/googletest.
Another cool thing is that I can run gclient sync from any subdirectory and it seems to find the .gclient file. That's kind of useful.
Ok, as a last task let's do a bit of cleanup. From within my_project, I get the following
$ git status HEAD detached at origin/master Untracked files: (use "git add..." to include in what will be committed) .DEPS.git third_party/
nothing added to commit but untracked files present (use "git add" to track)
I'll keep .DEPS.git, so I'll add it to the repo, but I don't want to add third_party or be constantly reminded about it, so I'll put third_party into .gitignore and add that instead.
$ git add .DEPS.git $ echo third_party > .gitignore $ git add .gitignore $ git status HEAD detached at origin/master Changes to be committed: (use "git reset HEAD..." to unstage) new file: .DEPS.git new file: .gitignore
Better. "HEAD detached at origin/master" is kind of worrying me though.
$ git commit -a [detached HEAD 4e6f8b3] Added deps and gitignore 2 files changed, 22 insertions(+) create mode 100644 .DEPS.git create mode 100644 .gitignore $ git push fatal: You are not currently on a branch. To push the history leading to the current (detached HEAD) state now, use git push origin HEAD:<name-of-remote-branch>
That sucks, I want to be on master when I sync initially. For now,
$ git push origin HEAD:master Counting objects: 5, done. Delta compression using up to 8 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (4/4), 661 bytes | 0 bytes/s, done. Total 4 (delta 0), reused 0 (delta 0) To ssh://example.com/repos/my_project.git ec01ec9..4e6f8b3 HEAD -> master $ git status HEAD detached from ec01ec9 nothing to commit, working directory clean $ gclient sync Syncing projects: 100% (2/2), done. $ git status HEAD detached from ec01ec9 nothing to commit, working directory clean $ git checkout master Previous HEAD position was 4e6f8b3... Added deps and gitignore Switched to branch 'master' Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch) $ gclient sync Syncing projects: 100% (2/2), done. $ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean
Ok, everything seems to be working. I'm hoping that I can add some sort of a hook to checkout master when syncing, as I don't want to always be remembering to checkout master. But that's for the next post.
- vmpstr
No comments:
Post a Comment