• Adding hooks to gclient deps


     

    In the previous several posts, we got to the point of being able to sync a git repo along with some dependencies. For reference, here's the .gclient file we created so far as well as the .DEPS.git from my_project directory:

    $ 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
    
    $ cat my_project/.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")
    }
    

    Now, in the last post, I noted that the initial checkout seems to happen in a detached state. That is, git status prints out something along the lines of the following:

    HEAD detached at origin/master
    

    I would like my initial checkouts to always go to the master branch, since I know I will forget to switch to the master branch when doing changes. This seems like a good application of a hook.

    As you recall, .DEPS.git from Chromium had a section called hooks. Great! I would imagine that's exactly what we want.

    The structure seems to be as follows:

    hooks = [
      {
        "name" : "hook_name",
        "pattern" : "hook_pattern",
        "action" : ["hook_action", "hook_action_parameter1"]
      }
    ]
    

    Name and action are fairly self explanatory, but I'm not too clear about what the pattern is supposed to represent. Run this hook only if something matches this pattern? That would make sense. However, most of the hooks in Chromium .DEPS.git have pattern as ".", so let's stick with that for now.

    Let's just jump in and add a simple hook into our .DEPS.git:

    ...
    hooks = [
      {
        "name" : "hello",
        "pattern" : ".",
        "action" : ["echo", "hello world!"]
      }
    ]
    

    This should do something:

    $ gclient runhooks
    
    ________ running 'echo hello world!' in '/tmp/learning_gclient'
    hello world!
    $ gclient sync
    Syncing projects: 100% (2/2), done.                             
    
    ________ running 'echo hello world!' in '/tmp/learning_gclient'
    hello world!
    

    Perfect! We can run hooks separately, and the hooks are run when we sync. That's exactly what we want. One observation I have is that it's probably a good idea to stick to some sort of a cross platform scripting language when writing hooks, since 'echo' on my machine might not exist on some other machine. Since gclient itself is written in python, it's a good bet that python is installed. As such, let's stick with python as the hooks language.

    Also note that we're running this hook in the same directory as the .gclient file (/tmp/learning_gclient in my case). Switching into my_project and running hooks again confirms that we're always running it from the same directory as the .gclient file. 

    Alright, let's just jump in and write a hook that checkout out master if the current state is "HEAD detached at origin/master". Learning python is out of the scope of this post, but after some googling on how to do things in it I came up with this:

    $ cat my_project/hooks/checkout_master.py
    import os
    from subprocess import Popen, PIPE
    
    def main():
      os.chdir("my_project")
      p = Popen(['git', 'status'], stdout=PIPE)
      output, err = p.communicate()
    
      line = output.splitlines()[0].strip()
      if line != 'HEAD detached at origin/master':
        print 'not an initial checkout, skip checkout master'
        return
    
      print 'checking out master branch'
      p = Popen(['git', 'checkout', 'master'], stdout=PIPE, stderr=PIPE)
      output, err = p.communicate()
      
    if __name__ == "__main__":
      main()
    

    Basically, we switch to my_project (I don't like hardcoding the project name here, but it will do for now), get the output of "git status", and if the first line of that is 'HEAD detached at origin/master', we run "git checkout master". Now, let's add this hook into our .DEPS.git, replacing the hello world one:

    ...
    hooks = [ 
      {
        "name" : "checkout_master",
        "pattern" : ".",
        "action" : ["python", Var("project_directory") + "/hooks/checkout_master.py"]
      }
    ]
    

    Let's see if that works as expected:

    $ gclient runhooks
    
    ________ running '/usr/bin/python my_project/hooks/checkout_master.py' in '/tmp/learning_gclient'
    not an initial checkout, skip checkout master
    

    Right, that's because during my testing, I already switched to the master branch. Let's just delete the whole project and sync again. However, remember to commit/push your changes. During my first attempt, I removed the directory and lost all of my changes (ie, I had to write the script and the hooks again).

    $ rm -rf my_project
    $ gclient sync
    Syncing projects: 100% (2/2), done.                             
    
    ________ running '/usr/bin/python my_project/hooks/checkout_master.py' in '/tmp/learning_gclient'
    checking out master branch
    $ cd my_project/
    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    
    nothing to commit, working directory clean
    

    Excellent! Everything seems to be working as intended. I think I'm happy enough with this basic gclient setup to move on to the actual build system using either GYP or GN.

    - vmpstr

    P.S. To eliminate the project name from checkout_master.py (thus making it a generic hook for any project), we should just move the project name to be a parameter. Here's a diff that makes it so:

    diff --git a/.DEPS.git b/.DEPS.git
    index 482ee29..56555cd 100644
    --- a/.DEPS.git
    +++ b/.DEPS.git
    @@ -23,6 +23,10 @@ hooks = [
       {
         "name" : "checkout_master",
         "pattern" : ".",
    -    "action" : ["python", Var("project_directory") + "/hooks/checkout_master.py"]
    +    "action" : [
    +      "python",
    +      Var("project_directory") + "/hooks/checkout_master.py",
    +      Var("project_directory")
    +    ]
       }
     ]
    diff --git a/hooks/checkout_master.py b/hooks/checkout_master.py
    index f41eefa..b5cf30a 100644
    --- a/hooks/checkout_master.py
    +++ b/hooks/checkout_master.py
    @@ -1,8 +1,10 @@
     import os
     from subprocess import Popen, PIPE
    +import sys
     
     def main():
    -  os.chdir("my_project")
    +  if len(sys.argv) == 2:
    +    os.chdir(sys.argv[1])
       p = Popen(['git', 'status'], stdout=PIPE)
       output, err = p.communicate()
  • 相关阅读:
    vue.js生成纵向拓扑图
    vue.js生成横向拓扑图
    Vue.js中使用wangEditor富文本编辑器
    文件上传与下载,PDF与Excel的操作
    Element布局实现日历布局
    golang时间转换
    iView学习笔记(四):Form表单操作
    iView学习笔记(三):表格搜索,过滤及隐藏列操作
    iView学习笔记(二):Table行编辑操作
    iView学习笔记(一):Table基本操作(包含前后端示例代码)
  • 原文地址:https://www.cnblogs.com/fire909090/p/11212209.html
Copyright © 2020-2023  润新知