Indeed.

I've worked around the issues, and have ported a few of my changes to
your script to make it work similarly to mine in my update environment.

I have more changes to port, but this is enough for now.

You'll see my documentation and --help updates on master-next.

Bruce


On Thu, Sep 7, 2023 at 10:31 PM ChenQi <qi.c...@windriver.com> wrote:
>
> On 9/8/23 05:09, Bruce Ashfield wrote:
> > On Tue, Sep 5, 2023 at 10:49 PM Bruce Ashfield via
> > lists.yoctoproject.org
> > <bruce.ashfield=gmail....@lists.yoctoproject.org> wrote:
> >> On Tue, Sep 5, 2023 at 10:41 PM ChenQi <qi.c...@windriver.com> wrote:
> >>> On 9/5/23 20:26, Bruce Ashfield wrote:
> >>>> On Mon, Sep 4, 2023 at 11:22 PM Chen Qi via lists.yoctoproject.org
> >>>> <Qi.Chen=windriver....@lists.yoctoproject.org> wrote:
> >>>>> From: Chen Qi <qi.c...@windriver.com>
> >>>>>
> >>>>> oe-go-mod-autogen.py is a helper script for go mod recipes. It follows
> >>>>> Bruce's initiative about how to deal with go mod recipes in OE.
> >>>>>
> >>>> I thought the techniques looked familiar!
> >>> Yes, indeed!
> >>>
> >>> With golang's current scheme, your approach is the only way to 1) make
> >>> these non-vendored go recipes build without network connection at
> >>> do_compile and 2) conform to OE's download mirroring mechanism. This
> >>> really helps a lot!
> >>>
> >>>> I was just working on my script before my holidays as my uprev cycle had
> >>>> taken me to the non-vendored go recipes and I was running into a few
> >>>> corner cases.
> >>>>
> >>>> I've got a K3S upgrade already done locally with my tweaked script, but
> >>>> I'll take this for a test run and see if I get the same results with 
> >>>> this.
> >>> I did use this script to upgrade k3s to 'v1.27.4+k3s1', only for the
> >>> purpose of verifying this script. Those three files were correctly
> >>> generated and the build succeeded. Hope you'll get the same result.
> >> I'm testing the k3s update now, and there are some differences, but
> >> they are minor and the vendoring looks good.
> >>
> >> I'll follow up once I've done a bit more testing.
> >>
> >> I can take care of a draft README for the script, and I will likely
> >> bring over a few of the elements of my script (the ability to do some
> >> module substitutions on the command line), but otherwise, I don't
> >> see a lot of gaps .
> > I've started on a README describing how to run the tool, and have
> > spent quite a bit of time with the script now (I was using more
> > heuristics to find the source repository, but using the go VCS
> > information makes things work much simpler .. which is of course
> > what you are doing).
> >
> > I've also ported some of my changes over (flags, and the ability
> > to track a branch (which I now realize I probably don't really need).
> >
> > That being said, k3s is now failing during processing:
> >
> > WARNING: Revision (ec00e662324e) not in
> > repo(/opt/bruce/poky/meta-virtualization/repos/nats.go)
> > WARNING: Failed to get requiredrev, repo_url =
> > https://github.com/nats-io/nats.go.git, rev = ec00e662324e,
> > module_name = github.com/nats-io/nats.go
> > WARNING: get_url_srcrev(github.com/nats-io/nats.go,
> > v1.27.1-0.20230619112143-ec00e662324e) failed
> >
> > I'm looking into that issue now.
> >
> > I had a more complicated semver regex to pull out the revisions, but in this
> > case, it does appear to be looking for the correct revision in the 
> > repository.
> >
> > I'm out of time for it today, but will continue working with it tomorrow.
> >
> > Bruce
> >
> Hi Bruce,
>
> Yes, I just double checked the https://github.com/nats-io/nats.go repo,
> the resivion 'ec00e662324e' does not exist.
>
> In k3s master branch, there's a commit to bump its version.
>
> -       github.com/nats-io/nats.go v1.27.1-0.20230619112143-ec00e662324e
> // indirect
> +       github.com/nats-io/nats.go v1.27.1 // indirect
>
> But for v1.27.5+k3s1, the go.mod file is using 'ec00e662324e'.
>
> I've filed an issue for k3s: https://github.com/k3s-io/k3s/issues/8320.
> Let's see how k3s community responds to this.
>
> Regards,
>
> Qi
>
>
> >> (I was doing things like generating the relocation and src_uri
> >> information in one run, and the modules.txt in another, but these
> >> aren't important features, so I'll won't worry about them
> >> when consolidating the tools).
> >>
> >> Bruce
> >>
> >>> Regards,
> >>>
> >>> Qi
> >>>
> >>>> I just didn't have the time to clean mine up to make it presentable, so
> >>>> I'm hopeful that this will work and I can take that off my TODO list!
> >>>>
> >>>> Bruce
> >>>>
> >>>>> Example:
> >>>>> cmd: <path_to>/meta-virtualization/scripts/oe-go-mod-autogen.py \
> >>>>>        --repo https://github.com/docker/compose --rev v2.20.3
> >>>>> output: src_uri.inc, relocation.inc, modules.txt
> >>>>>
> >>>>> Copy these three generated files to replace the original ones,
> >>>>> then we only need update PV and SRCREV, and docker-compose is upgraded.
> >>>>>
> >>>>> Below are some technical details.
> >>>>>
> >>>>> * get module's repo from module name
> >>>>>
> >>>>>     This script checks the following two URLs to determine the module's 
> >>>>> repo.
> >>>>>     1. https://<module_name_tweaked>?=go-get=1
> >>>>>     2. https://pkg.go.dev/<module_name_tweaked>
> >>>>>
> >>>>>     The module_name_tweaked is derived from module_name, with the last 
> >>>>> components
> >>>>>     removed one by one. Let me use two examples to explain this.
> >>>>>
> >>>>>     For module_name sigs.k8s.io/json, the sigs.k8s.io/json is first 
> >>>>> used as
> >>>>>     module_name_tweaked for searching. And we can correctly get the 
> >>>>> repo URL, so
> >>>>>     the search stops.
> >>>>>
> >>>>>     For module_name github.com/k3s-io/etcd/api/v3, the following ones 
> >>>>> are used
> >>>>>     as module_name_tweaked:
> >>>>>     github.com/k3s-io/etcd/api/v3
> >>>>>     github.com/k3s-io/etcd/api
> >>>>>     github.com/k3s-io/etcd
> >>>>>     And when searching 'github.com/k3s-io/etcd', we get the repo URL, 
> >>>>> so the search
> >>>>>     stops.
> >>>>>
> >>>>> * determine the srcdir:destdir mapping in 'vendor' creation
> >>>>>
> >>>>>     To correctly form the 'vendor' directory, the mapping is critical.
> >>>>>     This script makes use of tag matching and path matching to determine
> >>>>>     the subpath in the repo for the module.
> >>>>>
> >>>>> * avoid subpath being overriden by parent path
> >>>>>
> >>>>>     We need to avoid subpath being overriden by parent path. This is 
> >>>>> needed
> >>>>>     for both SRC_URI ordering in src_uri.inc and the sites mapping 
> >>>>> ordering
> >>>>>     in relocation.inc. This script simply uses the length as the 
> >>>>> ordering key,
> >>>>>     simply for the reason that if a path is a subpath of another path, 
> >>>>> it must
> >>>>>     be longer.
> >>>>>
> >>>>> * the .git suffix is removed to sync with each other
> >>>>>
> >>>>>     Unlike normal recipes, go mod recipe usually have many SRC_URIs. 
> >>>>> This script
> >>>>>     remove the '.git' suffix from repo URL so that the repo URLs are in 
> >>>>> sync
> >>>>>     with each.
> >>>>>
> >>>>> * basic directory hierarchy and caching mechanism
> >>>>>
> >>>>>     <cwd>/repos: hold the repos downloaded and checked
> >>>>>     <cwd>/wget-contents: hold the contents to determine the module's 
> >>>>> repo
> >>>>>     <cwd>/wget-contents/<module_name>.repo_url.cache: the repo value 
> >>>>> cache
> >>>>>     This is to avoid unnecessary URL fetching and repo cloning.
> >>>>>
> >>>>> * the ERROR_OUT_ON_FETCH_AND_CHECKOUT_FAILURE switch in script
> >>>>>
> >>>>>     The script must get the correct repo_url, fullsrc_rev and subpath 
> >>>>> for
> >>>>>     each required module in go.mod to correctly generate the 
> >>>>> src_uri.inc and
> >>>>>     relocation.inc files. If this process fails for any required 
> >>>>> module, this
> >>>>>     script stop immediately, as I deliberately set 
> >>>>> ERROR_OUT_ON_FETCH_AND_CHECKOUT_FAILURE
> >>>>>     to True in this script. The purpose is to encourage people to report
> >>>>>     problems to meta-virt so that we can improve this script according 
> >>>>> to
> >>>>>     these feedbacks. But this variable can set to False, then the script
> >>>>>     only records the failed modules in self.modules_unhandled with 
> >>>>> reasons
> >>>>>     added, people can modify the generated src_uri.inc and 
> >>>>> relocation.inc
> >>>>>     to manually handle these unhandled modules if they are urgent to
> >>>>>     add/upgrade some go mod recipes.
> >>>>>
> >>>>> Signed-off-by: Chen Qi <qi.c...@windriver.com>
> >>>>> ---
> >>>>>    scripts/oe-go-mod-autogen.py | 663 
> >>>>> +++++++++++++++++++++++++++++++++++
> >>>>>    1 file changed, 663 insertions(+)
> >>>>>    create mode 100755 scripts/oe-go-mod-autogen.py
> >>>>>
> >>>>> diff --git a/scripts/oe-go-mod-autogen.py b/scripts/oe-go-mod-autogen.py
> >>>>> new file mode 100755
> >>>>> index 00000000..09d6133b
> >>>>> --- /dev/null
> >>>>> +++ b/scripts/oe-go-mod-autogen.py
> >>>>> @@ -0,0 +1,663 @@
> >>>>> +#!/usr/bin/env python3
> >>>>> +
> >>>>> +import os
> >>>>> +import sys
> >>>>> +import logging
> >>>>> +import argparse
> >>>>> +from collections import OrderedDict
> >>>>> +import subprocess
> >>>>> +
> >>>>> +# This switch is used to make this script error out ASAP, mainly for 
> >>>>> debugging purpose
> >>>>> +ERROR_OUT_ON_FETCH_AND_CHECKOUT_FAILURE = True
> >>>>> +
> >>>>> +logger = logging.getLogger('oe-go-mod-autogen')
> >>>>> +loggerhandler = logging.StreamHandler()
> >>>>> +loggerhandler.setFormatter(logging.Formatter("%(levelname)s: 
> >>>>> %(message)s"))
> >>>>> +logger.addHandler(loggerhandler)
> >>>>> +logger.setLevel(logging.INFO)
> >>>>> +
> >>>>> +class GoModTool(object):
> >>>>> +    def __init__(self, repo, rev, workdir):
> >>>>> +        self.repo = repo
> >>>>> +        self.rev = rev
> >>>>> +        self.workdir = workdir
> >>>>> +
> >>>>> +        # Stores the actual module name and its related information
> >>>>> +        # {module: (repo_url, repo_dest_dir, fullsrcrev)}
> >>>>> +        self.modules_repoinfo = {}
> >>>>> +
> >>>>> +        # {module_name: (url, version, destdir, fullsrcrev)}
> >>>>> +        #
> >>>>> +        # url: place to get the source codes, we only support git repo
> >>>>> +        # version: module version, git tag or git rev
> >>>>> +        # destdir: place to put the fetched source codes
> >>>>> +        # fullsrcrev: full src rev which is the value of SRC_REV
> >>>>> +        #
> >>>>> +        # e.g.
> >>>>> +        # For 'github.com/Masterminds/semver/v3 v3.1.1' in go.mod:
> >>>>> +        # module_name = github.com/Masterminds/semver/v3
> >>>>> +        # url = https://github.com/Masterminds/semver
> >>>>> +        # version = v3.1.1
> >>>>> +        # destdir = 
> >>>>> ${WORKDIR}/${BP}/src/${GO_IMPORT}/vendor/github.com/Masterminds/semver/v3
> >>>>> +        # fullsrcrev = d387ce7889a157b19ad7694dba39a562051f41b0
> >>>>> +        self.modules_require = OrderedDict()
> >>>>> +
> >>>>> +        # {orig_module: (actual_module, actual_version)}
> >>>>> +        self.modules_replace = OrderedDict()
> >>>>> +
> >>>>> +        # Unhandled modules
> >>>>> +        self.modules_unhandled = OrderedDict()
> >>>>> +
> >>>>> +        # store subpaths used to form srcpath
> >>>>> +        # {actual_module_name: subpath}
> >>>>> +        self.modules_subpaths = OrderedDict()
> >>>>> +
> >>>>> +        # modules's actual source paths, record those that are not the 
> >>>>> same with the module itself
> >>>>> +        self.modules_srcpaths = OrderedDict()
> >>>>> +
> >>>>> +        # store lines, comment removed
> >>>>> +        self.require_lines = []
> >>>>> +        self.replace_lines = []
> >>>>> +
> >>>>> +        # fetch repo
> >>>>> +        self.fetch_and_checkout_repo(self.repo.split('://')[1], 
> >>>>> self.repo, self.rev, checkout=True, get_subpath=False)
> >>>>> +
> >>>>> +    def show_go_mod_info(self):
> >>>>> +        # Print modules_require, modules_replace and modules_unhandled
> >>>>> +        print("modules required:")
> >>>>> +        for m in self.modules_require:
> >>>>> +            url, version, destdir, fullrev = self.modules_require[m]
> >>>>> +            print("%s %s %s %s" % (m, version, url, fullrev))
> >>>>> +
> >>>>> +        print("modules replace:")
> >>>>> +        for m in self.modules_replace:
> >>>>> +            actual_module, actual_version = self.modules_replace[m]
> >>>>> +            print("%s => %s %s" % (m, actual_module, actual_version))
> >>>>> +
> >>>>> +        print("modules unhandled:")
> >>>>> +        for m in self.modules_unhandled:
> >>>>> +            reason = self.modules_unhandled[m]
> >>>>> +            print("%s unhandled: %s" % (m, reason))
> >>>>> +
> >>>>> +    def parse(self):
> >>>>> +        # check if this repo needs autogen
> >>>>> +        repo_url, repo_dest_dir, repo_fullrev = 
> >>>>> self.modules_repoinfo[self.repo.split('://')[1]]
> >>>>> +        if os.path.isdir(os.path.join(repo_dest_dir, 'vendor')):
> >>>>> +            logger.info("vendor direcotry has already existed for %s, 
> >>>>> no need to add other repos" % self.repo)
> >>>>> +            return
> >>>>> +        go_mod_file = os.path.join(repo_dest_dir, 'go.mod')
> >>>>> +        if not os.path.exists(go_mod_file):
> >>>>> +            logger.info("go.mod file does not exist for %s, no need to 
> >>>>> add otehr repos" % self.repo)
> >>>>> +            return
> >>>>> +        self.parse_go_mod(go_mod_file)
> >>>>> +        self.show_go_mod_info()
> >>>>> +
> >>>>> +    def fetch_and_checkout_repo(self, module_name, repo_url, rev, 
> >>>>> default_protocol='https://', checkout=False, get_subpath=True):
> >>>>> +        """
> >>>>> +        Fetch repo_url to <workdir>/repos/repo_base_name
> >>>>> +        """
> >>>>> +        protocol = default_protocol
> >>>>> +        if '://' in repo_url:
> >>>>> +            repo_url_final = repo_url
> >>>>> +        else:
> >>>>> +            repo_url_final = default_protocol + repo_url
> >>>>> +        logger.debug("fetch and checkout %s %s" % (repo_url_final, 
> >>>>> rev))
> >>>>> +        repos_dir = os.path.join(self.workdir, 'repos')
> >>>>> +        if not os.path.exists(repos_dir):
> >>>>> +            os.makedirs(repos_dir)
> >>>>> +        repo_basename = repo_url.split('/')[-1].split('.git')[0]
> >>>>> +        repo_dest_dir = os.path.join(repos_dir, repo_basename)
> >>>>> +        module_last_name = module_name.split('/')[-1]
> >>>>> +        git_action = "fetch"
> >>>>> +        if os.path.exists(repo_dest_dir):
> >>>>> +            if checkout:
> >>>>> +                # check if current HEAD is rev
> >>>>> +                try:
> >>>>> +                    headrev = subprocess.check_output('git rev-list -1 
> >>>>> HEAD', shell=True, cwd=repo_dest_dir).decode('utf-8').strip()
> >>>>> +                    requiredrev = subprocess.check_output('git 
> >>>>> rev-list -1 %s 2>/dev/null || git rev-list -1 %s/%s' % (rev, 
> >>>>> module_last_name, rev), shell=True, 
> >>>>> cwd=repo_dest_dir).decode('utf-8').strip()
> >>>>> +                    if headrev == requiredrev:
> >>>>> +                        logger.info("%s has already been fetched and 
> >>>>> checked out as required, skipping" % repo_url)
> >>>>> +                        self.modules_repoinfo[module_name] = 
> >>>>> (repo_url, repo_dest_dir, requiredrev)
> >>>>> +                        return
> >>>>> +                    else:
> >>>>> +                        logger.info("HEAD of %s is not %s, will do a 
> >>>>> clean clone" % (repo_dest_dir, requiredrev))
> >>>>> +                        git_action = "clone"
> >>>>> +                except:
> >>>>> +                    logger.info("'git rev-list' in %s failed, will do 
> >>>>> a clean clone" % repo_dest_dir)
> >>>>> +                    git_action = "clone"
> >>>>> +            else:
> >>>>> +                # determine if the current repo points to the desired 
> >>>>> remote repo
> >>>>> +                try:
> >>>>> +                    remote_origin_url = subprocess.check_output('git 
> >>>>> config --get remote.origin.url', shell=True, 
> >>>>> cwd=repo_dest_dir).decode('utf-8').strip()
> >>>>> +                    if remote_origin_url.endswith('.git'):
> >>>>> +                        if not repo_url_final.endswith('.git'):
> >>>>> +                            remote_origin_url = remote_origin_url[:-4]
> >>>>> +                    else:
> >>>>> +                        if repo_url_final.endswith('.git'):
> >>>>> +                            remote_origin_url = remote_origin_url + 
> >>>>> '.git'
> >>>>> +                    if remote_origin_url != repo_url_final:
> >>>>> +                        logger.info("remote.origin.url for %s is not 
> >>>>> %s, will do a clean clone" % (repo_dest_dir, repo_url_final))
> >>>>> +                        git_action = "clone"
> >>>>> +                except:
> >>>>> +                    logger.info("'git config --get remote.origin.url' 
> >>>>> in %s failed, will do a clean clone" % repo_dest_dir)
> >>>>> +                    git_action = "clone"
> >>>>> +        else:
> >>>>> +            # No local repo, clone it.
> >>>>> +            git_action = "clone"
> >>>>> +
> >>>>> +        if git_action == "clone":
> >>>>> +            logger.info("Removing %s" % repo_dest_dir)
> >>>>> +            subprocess.check_call('rm -rf %s' % repo_dest_dir, 
> >>>>> shell=True)
> >>>>> +
> >>>>> +        # clone/fetch repo
> >>>>> +        try:
> >>>>> +            git_cwd = repos_dir if git_action == "clone" else 
> >>>>> repo_dest_dir
> >>>>> +            logger.info("git %s %s in %s" % (git_action, 
> >>>>> repo_url_final, git_cwd))
> >>>>> +            subprocess.check_call('git %s %s >/dev/null 2>&1' % 
> >>>>> (git_action, repo_url_final), shell=True, cwd=git_cwd)
> >>>>> +        except:
> >>>>> +            logger.warning("Failed to %s %s in %s" % (git_action, 
> >>>>> repo_url_final, git_cwd))
> >>>>> +            return
> >>>>> +
> >>>>> +        def get_requiredrev(get_subpath):
> >>>>> +            import re
> >>>>> +            # check if rev is a revision or a version
> >>>>> +            if len(rev) == 12 and re.match('[0-9a-f]+', rev):
> >>>>> +                rev_is_version = False
> >>>>> +            else:
> >>>>> +                rev_is_version = True
> >>>>> +
> >>>>> +            # if rev is not a version, 'git rev-list -1 <rev>' should 
> >>>>> just succeed!
> >>>>> +            if not rev_is_version:
> >>>>> +                try:
> >>>>> +                    rev_return = subprocess.check_output('git rev-list 
> >>>>> -1 %s 2>/dev/null' % rev, shell=True, 
> >>>>> cwd=repo_dest_dir).decode('utf-8').strip()
> >>>>> +                    if get_subpath:
> >>>>> +                        cmd = 'git branch -M toremove && git checkout 
> >>>>> -b check_subpath %s && git branch -D toremove' % rev_return
> >>>>> +                        subprocess.check_call(cmd, shell=True, 
> >>>>> cwd=repo_dest_dir)
> >>>>> +                        # try to get the subpath for this module
> >>>>> +                        module_name_parts = module_name.split('/')
> >>>>> +                        while (len(module_name_parts) > 0):
> >>>>> +                            subpath = '/'.join(module_name_parts)
> >>>>> +                            dir_to_check = repo_dest_dir + '/' + 
> >>>>> '/'.join(module_name_parts)
> >>>>> +                            if os.path.isdir(dir_to_check):
> >>>>> +                                self.modules_subpaths[module_name] = 
> >>>>> subpath
> >>>>> +                                break
> >>>>> +                            else:
> >>>>> +                                module_name_parts.pop(0)
> >>>>> +                    return rev_return
> >>>>> +                except:
> >>>>> +                    logger.warning("Revision (%s) not in repo(%s)" % 
> >>>>> (rev, repo_dest_dir))
> >>>>> +                    return None
> >>>>> +
> >>>>> +            # the following codes deals with case where rev is a 
> >>>>> version
> >>>>> +            # determine the longest match tag, in this way, we can get 
> >>>>> the current srcpath to be used in relocation.inc
> >>>>> +            # we first get the initial tag, which is formed from 
> >>>>> module_name and rev
> >>>>> +            module_parts = module_name.split('/')
> >>>>> +            if rev.startswith(module_parts[-1] + '.'):
> >>>>> +                tag = '/'.join(module_parts[:-1]) + '/' + rev
> >>>>> +                last_module_part_replaced = True
> >>>>> +            else:
> >>>>> +                tag = '/'.join(module_parts) + '/' + rev
> >>>>> +                last_module_part_replaced = False
> >>>>> +            logger.debug("use %s as the initial tag for %s" % (tag, 
> >>>>> module_name))
> >>>>> +            tag_parts = tag.split('/')
> >>>>> +            while(len(tag_parts) > 0):
> >>>>> +                try:
> >>>>> +                    rev_return = subprocess.check_output('git rev-list 
> >>>>> -1 %s 2>/dev/null' % tag, shell=True, 
> >>>>> cwd=repo_dest_dir).decode('utf-8').strip()
> >>>>> +                    if len(tag_parts) > 1:
> >>>>> +                        # ensure that the subpath exists
> >>>>> +                        if get_subpath:
> >>>>> +                            cmd = 'git branch -M toremove && git 
> >>>>> checkout -b check_subpath %s && git branch -D toremove' % rev_return
> >>>>> +                            subprocess.check_call(cmd, shell=True, 
> >>>>> cwd=repo_dest_dir)
> >>>>> +                            # get subpath for the actual_module_name
> >>>>> +                            if last_module_part_replaced:
> >>>>> +                                subpath = '/'.join(tag_parts[:-1]) + 
> >>>>> '/' + module_parts[-1]
> >>>>> +                                if not os.path.isdir(repo_dest_dir + 
> >>>>> '/' + subpath):
> >>>>> +                                    subpath = '/'.join(tag_parts[:-1])
> >>>>> +                            else:
> >>>>> +                                subpath = '/'.join(tag_parts[:-1])
> >>>>> +                            if not os.path.isdir(repo_dest_dir + '/' + 
> >>>>> subpath):
> >>>>> +                                logger.warning("subpath (%s) derived 
> >>>>> from tag matching does not exist in %s" % (subpath, repo_dest_dir))
> >>>>> +                                return None
> >>>>> +                            self.modules_subpaths[module_name] = 
> >>>>> subpath
> >>>>> +                            logger.info("modules_subpath[%s] = %s" % 
> >>>>> (module_name, subpath))
> >>>>> +                    return rev_return
> >>>>> +                except:
> >>>>> +                    tag_parts.pop(0)
> >>>>> +                    tag = '/'.join(tag_parts)
> >>>>> +            logger.warning("No tag matching %s" % rev)
> >>>>> +            return None
> >>>>> +
> >>>>> +        requiredrev = get_requiredrev(get_subpath)
> >>>>> +        if requiredrev:
> >>>>> +            logger.info("Got module(%s) requiredrev: %s" % 
> >>>>> (module_name, requiredrev))
> >>>>> +            if checkout:
> >>>>> +                subprocess.check_call('git checkout -b gomodautogen 
> >>>>> %s' % requiredrev, shell=True, cwd=repo_dest_dir)
> >>>>> +            self.modules_repoinfo[module_name] = (repo_url, 
> >>>>> repo_dest_dir, requiredrev)
> >>>>> +        else:
> >>>>> +            logger.warning("Failed to get requiredrev, repo_url = %s, 
> >>>>> rev = %s, module_name = %s" % (repo_url, rev, module_name))
> >>>>> +
> >>>>> +    def parse_go_mod(self, go_mod_path):
> >>>>> +        """
> >>>>> +        Parse go.mod file to get the modules info
> >>>>> +        """
> >>>>> +        # First we get the require and replace lines
> >>>>> +        # The parsing logic assumes the replace lines come *after* the 
> >>>>> require lines
> >>>>> +        inrequire = False
> >>>>> +        inreplace = False
> >>>>> +        with open(go_mod_path, 'r') as f:
> >>>>> +            lines = f.readlines()
> >>>>> +            for line in lines:
> >>>>> +                if line.startswith('require ('):
> >>>>> +                    inrequire = True
> >>>>> +                    continue
> >>>>> +                if line.startswith(')'):
> >>>>> +                    inrequire = False
> >>>>> +                    continue
> >>>>> +                if line.startswith('require ') or inrequire:
> >>>>> +                    # we have one line require
> >>>>> +                    require_line = line.lstrip('require 
> >>>>> ').split('//')[0].strip()
> >>>>> +                    if require_line:
> >>>>> +                        self.require_lines.append(require_line)
> >>>>> +                    continue
> >>>>> +                # we can deal with requires and replaces separately 
> >>>>> because go.mod always writes requires before replaces
> >>>>> +                if line.startswith('replace ('):
> >>>>> +                    inreplace = True
> >>>>> +                    continue
> >>>>> +                if line.startswith(')'):
> >>>>> +                    inreplace = False
> >>>>> +                    continue
> >>>>> +                if line.startswith('replace ') or inreplace:
> >>>>> +                    replace_line = line.lstrip('replace 
> >>>>> ').split('//')[0].strip()
> >>>>> +                    if replace_line:
> >>>>> +                        self.replace_lines.append(replace_line)
> >>>>> +                    continue
> >>>>> +        #
> >>>>> +        # parse the require_lines and replace_lines to form 
> >>>>> self.modules_require and self.modules_replace
> >>>>> +        #
> >>>>> +        logger.debug("Parsing require_lines and replace_lines ...")
> >>>>> +        # A typical replace line is as below:
> >>>>> +        #   github.com/hashicorp/golang-lru => 
> >>>>> github.com/ktock/golang-lru v0.5.5-0.20211029085301-ec551be6f75c
> >>>>> +        # It means that the github.com/hashicorp/golang-lru module is 
> >>>>> replaced by github.com/ktock/golang-lru
> >>>>> +        # with the version 'v0.5.5-0.20211029085301-ec551be6f75c'.
> >>>>> +        # So the destdir is vendor/github.com/hashicorp/golang-lru 
> >>>>> while the contents are from github.com/ktock/golang-lru
> >>>>> +        for line in self.replace_lines:
> >>>>> +            orig_module, actual = line.split('=>')
> >>>>> +            actual_module, actual_version = actual.split()
> >>>>> +            orig_module = orig_module.strip()
> >>>>> +            actual_module = actual_module.strip()
> >>>>> +            actual_version = actual_version.strip()
> >>>>> +            self.modules_replace[orig_module] = (actual_module, 
> >>>>> actual_version)
> >>>>> +        #
> >>>>> +        # Typical require lines are as below:
> >>>>> +        #   github.com/Masterminds/semver/v3 v3.1.1
> >>>>> +        #   golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
> >>>>> +        #
> >>>>> +        # We need to first try https://<module_name>?=go-get=1 to see 
> >>>>> it contains
> >>>>> +        # line starting with '<meta name="go-import" content='.
> >>>>> +        #
> >>>>> +        # If so, get root-path vcs repo-url from content. See 
> >>>>> https://go.dev/ref/mod#vcs-find
> >>>>> +        # For example, the above 'wget 
> >>>>> https://golang.org/x/crypto?go-get=1' gives you
> >>>>> +        # <meta name="go-import" content="golang.org/x/crypto git 
> >>>>> https://go.googlesource.com/crypto";>
> >>>>> +        # In such case, the self.modules_require has the following 
> >>>>> contents:
> >>>>> +        # module_name: golang.org/x/crypto
> >>>>> +        # url: https://go.googlesource.com/crypto
> >>>>> +        # version: v0.0.0-20220321153916-2c7772ba3064
> >>>>> +        # destdir: 
> >>>>> ${WORKDIR}/${BP}/src/import/vendor.fetch/golang.org/x/crypto
> >>>>> +        # fullsrcrev: 2c7772ba30643b7a2026cbea938420dce7c6384d (git 
> >>>>> rev-list -1 2c7772ba3064)
> >>>>> +        #
> >>>>> +        # If not, try https://pkg.go.dev/<module_name>, and find the 
> >>>>> 'Repository'.
> >>>>> +        # For example, 'wget 
> >>>>> https://pkg.go.dev/github.com/Masterminds/semver/v3' gives:
> >>>>> +        # github.com/Masterminds/semver
> >>>>> +        # In such case, the self.modules has the following contents:
> >>>>> +        # module_name: github.com/Masterminds/semver/v3
> >>>>> +        # url: https://github.com/Masterminds/semver
> >>>>> +        # version: v3.1.1
> >>>>> +        # destdir: 
> >>>>> ${WORKDIR}/${BP}/src/import/vendor.fetch/github.com/Masterminds/semver/v3
> >>>>> +        # fullsrcrev: 7bb0c843b53d6ad21a3f619cb22c4b442bb3ef3e (git 
> >>>>> rev-list -1 v3.1.1)
> >>>>> +        #
> >>>>> +        # As a last resort, if the last component of <module_name> 
> >>>>> matches 'v[0-9]+',
> >>>>> +        # remove the last component and try wget 
> >>>>> https://<module_name_with_last_component_removed>?go-get=1,
> >>>>> +        # then try using the above matching method.
> >>>>> +        #
> >>>>> +        for line in self.require_lines:
> >>>>> +            module_name, version = line.strip().split()
> >>>>> +            logger.debug("require line: %s" % line)
> >>>>> +            logger.debug("module_name = %s; version = %s" % 
> >>>>> (module_name, version))
> >>>>> +            # take the modules_replace into consideration to get the 
> >>>>> actual version and actual module name
> >>>>> +            # note that the module_name is used in destdir, and the 
> >>>>> actual_module_name and actual_version
> >>>>> +            # are used to determine the url and fullsrcrev
> >>>>> +            destdir = '${WORKDIR}/${BP}/src/import/vendor.fetch/%s' % 
> >>>>> module_name
> >>>>> +            actual_module_name = module_name
> >>>>> +            actual_version = version
> >>>>> +            if module_name in self.modules_replace:
> >>>>> +                actual_module_name, actual_version = 
> >>>>> self.modules_replace[module_name]
> >>>>> +            logger.debug("actual_module_name = %s; actual_version = 
> >>>>> %s" % (actual_module_name, actual_version))
> >>>>> +            url, fullsrcrev = self.get_url_srcrev(actual_module_name, 
> >>>>> actual_version)
> >>>>> +            logger.debug("url = %s; fullsrcrev = %s" % (url, 
> >>>>> fullsrcrev))
> >>>>> +            if url and fullsrcrev:
> >>>>> +                self.modules_require[module_name] = (url, version, 
> >>>>> destdir, fullsrcrev)
> >>>>> +                # form srcpath, actual_module_name/<subpath>
> >>>>> +                if actual_module_name in self.modules_subpaths:
> >>>>> +                    subpath = self.modules_subpaths[actual_module_name]
> >>>>> +                    srcpath = '%s/%s' % (actual_module_name, subpath)
> >>>>> +                    self.modules_srcpaths[module_name] = srcpath
> >>>>> +                    logger.info("self.modules_srcpaths[%s] = %s" % 
> >>>>> (module_name, srcpath))
> >>>>> +                else:
> >>>>> +                    self.modules_srcpaths[module_name] = 
> >>>>> actual_module_name
> >>>>> +            else:
> >>>>> +                logger.warning("get_url_srcrev(%s, %s) failed" % 
> >>>>> (actual_module_name, actual_version))
> >>>>> +                if ERROR_OUT_ON_FETCH_AND_CHECKOUT_FAILURE:
> >>>>> +                    sys.exit(1)
> >>>>> +
> >>>>> +    def use_wget_to_get_repo_url(self, wget_content_file, 
> >>>>> url_cache_file, module_name):
> >>>>> +        """
> >>>>> +        Use wget to get repo_url for module_name, return None if not 
> >>>>> found
> >>>>> +        """
> >>>>> +        try:
> >>>>> +            logger.info("wget -O %s https://%s?=go-get=1"; % 
> >>>>> (wget_content_file, module_name))
> >>>>> +            subprocess.check_call('wget -O %s https://%s?=go-get=1' % 
> >>>>> (wget_content_file, module_name), shell=True)
> >>>>> +            with open(wget_content_file, 'r') as f:
> >>>>> +                for line in f.readlines():
> >>>>> +                    if '<meta name="go-import" content=' in line:
> >>>>> +                        logger.info("Succeed to find go-import content 
> >>>>> for %s" % module_name)
> >>>>> +                        logger.debug("The line is %s" % line)
> >>>>> +                        root_path, vcs, repo_url = 
> >>>>> line.split('content=')[1].split('"')[1].split()
> >>>>> +                        logger.info("%s: %s %s %s" % (module_name, 
> >>>>> root_path, vcs, repo_url))
> >>>>> +                        if vcs != 'git':
> >>>>> +                            logger.warning('%s unhandled as its vcs is 
> >>>>> %s which is not supported by this script.' % (module_name, vcs))
> >>>>> +                            unhandled_reason = 'vcs %s is not 
> >>>>> supported by this script' % vcs
> >>>>> +                            self.modules_unhandled[module_name] = 
> >>>>> unhandled_reason
> >>>>> +                            return None
> >>>>> +                        with open(url_cache_file, 'w') as f:
> >>>>> +                            f.write(repo_url)
> >>>>> +                        return repo_url
> >>>>> +        except:
> >>>>> +            logger.info("wget -O %s https://%s?=go-get=1 failed" % 
> >>>>> (wget_content_file, module_name))
> >>>>> +        # if we cannot find repo url from 
> >>>>> https://<module_name>?=go-get=1, try https://pkg.go/dev/<module_name>
> >>>>> +        try:
> >>>>> +            logger.info("wget -O %s https://pkg.go.dev/%s"; % 
> >>>>> (wget_content_file, module_name))
> >>>>> +            subprocess.check_call("wget -O %s https://pkg.go.dev/%s"; % 
> >>>>> (wget_content_file, module_name), shell=True)
> >>>>> +            repo_url_found = False
> >>>>> +            with open(wget_content_file, 'r') as f:
> >>>>> +                in_repo_section = False
> >>>>> +                for line in f.readlines():
> >>>>> +                    if '>Repository<' in line:
> >>>>> +                        in_repo_section = True
> >>>>> +                        continue
> >>>>> +                    if in_repo_section:
> >>>>> +                        newline = line.strip()
> >>>>> +                        if newline != '' and not 
> >>>>> newline.startswith('<'):
> >>>>> +                            repo_url = newline
> >>>>> +                            repo_url_found = True
> >>>>> +                            break
> >>>>> +            if repo_url_found:
> >>>>> +                logger.info("repo url for %s: %s" % (module_name, 
> >>>>> repo_url))
> >>>>> +                with open(url_cache_file, 'w') as f:
> >>>>> +                    f.write(repo_url)
> >>>>> +                return repo_url
> >>>>> +            else:
> >>>>> +                unhandled_reason = 'cannot determine repo_url for %s' 
> >>>>> % module_name
> >>>>> +                self.modules_unhandled[module_name] = unhandled_reason
> >>>>> +                return None
> >>>>> +        except:
> >>>>> +            logger.info("wget -O %s https://pkg.go.dev/%s failed" % 
> >>>>> (wget_content_file, module_name))
> >>>>> +            return None
> >>>>> +
> >>>>> +
> >>>>> +    def get_repo_url_rev(self, module_name, version):
> >>>>> +        """
> >>>>> +        Return (repo_url, rev)
> >>>>> +        """
> >>>>> +        import re
> >>>>> +        # First get rev from version
> >>>>> +        v = version.split('+incompatible')[0]
> >>>>> +        version_components = v.split('-')
> >>>>> +        if len(version_components) == 1:
> >>>>> +            rev = v
> >>>>> +        elif len(version_components) == 3:
> >>>>> +            if len(version_components[2]) == 12:
> >>>>> +                rev = version_components[2]
> >>>>> +            else:
> >>>>> +                rev = v
> >>>>> +        else:
> >>>>> +            rev = v
> >>>>> +
> >>>>> +        #
> >>>>> +        # Get repo_url
> >>>>> +        # We put a cache mechanism here, 
> >>>>> <wget_content_file>.repo_url.cache is used to store the repo url fetch 
> >>>>> before
> >>>>> +        #
> >>>>> +        wget_dir = os.path.join(self.workdir, 'wget-contents')
> >>>>> +        if not os.path.exists(wget_dir):
> >>>>> +            os.makedirs(wget_dir)
> >>>>> +        wget_content_file = os.path.join(wget_dir, 
> >>>>> module_name.replace('/', '_'))
> >>>>> +        url_cache_file = "%s.repo_url.cache" % wget_content_file
> >>>>> +        if os.path.exists(url_cache_file):
> >>>>> +            with open(url_cache_file, 'r') as f:
> >>>>> +                repo_url = f.readline().strip()
> >>>>> +                return (repo_url, rev)
> >>>>> +        module_name_parts = module_name.split('/')
> >>>>> +        while (len(module_name_parts) > 0):
> >>>>> +            module_name_to_check = '/'.join(module_name_parts)
> >>>>> +            logger.info("module_name_to_check: %s" % 
> >>>>> module_name_to_check)
> >>>>> +            repo_url = 
> >>>>> self.use_wget_to_get_repo_url(wget_content_file, url_cache_file, 
> >>>>> module_name_to_check)
> >>>>> +            if repo_url:
> >>>>> +                return (repo_url, rev)
> >>>>> +            else:
> >>>>> +                if module_name in self.modules_unhandled:
> >>>>> +                    return (None, rev)
> >>>>> +                else:
> >>>>> +                    module_name_parts.pop(-1)
> >>>>> +
> >>>>> +        unhandled_reason = 'cannot determine the repo for %s' % 
> >>>>> module_name
> >>>>> +        self.modules_unhandled[module_name] = unhandled_reason
> >>>>> +        return (None, rev)
> >>>>> +
> >>>>> +    def get_url_srcrev(self, module_name, version):
> >>>>> +        """
> >>>>> +        Return url and fullsrcrev according to module_name and version
> >>>>> +        """
> >>>>> +        repo_url, rev = self.get_repo_url_rev(module_name, version)
> >>>>> +        if not repo_url or not rev:
> >>>>> +            return (None, None)
> >>>>> +        self.fetch_and_checkout_repo(module_name, repo_url, rev)
> >>>>> +        if module_name in self.modules_repoinfo:
> >>>>> +            repo_url, repo_dest_dir, repo_fullrev = 
> >>>>> self.modules_repoinfo[module_name]
> >>>>> +            # remove the .git suffix to sync repos across modules with 
> >>>>> different versions and across recipes
> >>>>> +            if repo_url.endswith('.git'):
> >>>>> +                repo_url = repo_url[:-len('.git')]
> >>>>> +            return (repo_url, repo_fullrev)
> >>>>> +        else:
> >>>>> +            unhandled_reason = 'fetch_and_checkout_repo(%s, %s, %s) 
> >>>>> failed' % (module_name, repo_url, rev)
> >>>>> +            self.modules_unhandled[module_name] = unhandled_reason
> >>>>> +            return (None, None)
> >>>>> +
> >>>>> +    def gen_src_uri_inc(self):
> >>>>> +        """
> >>>>> +        Generate src_uri.inc file containing SRC_URIs
> >>>>> +        """
> >>>>> +        src_uri_inc_file = os.path.join(self.workdir, 'src_uri.inc')
> >>>>> +        # record the <name> after writting SRCREV_<name>, this is to 
> >>>>> avoid modules having the same basename resulting in same SRCREV_xxx
> >>>>> +        srcrev_name_recorded = []
> >>>>> +        template = """#       %s %s
> >>>>> +# [1] git ls-remote %s %s
> >>>>> +SRCREV_%s="%s"
> >>>>> +SRC_URI += 
> >>>>> "git://%s;name=%s;protocol=https;nobranch=1;destsuffix=${WORKDIR}/${BP}/src/import/vendor.fetch/%s"
> >>>>> +
> >>>>> +"""
> >>>>> +        # We can't simply write SRC_URIs one by one in the order that 
> >>>>> go.mod specify them.
> >>>>> +        # Because the latter one might clean things up for the former 
> >>>>> one if the former one is a subpath of the latter one.
> >>>>> +        def take_first_len(elem):
> >>>>> +            return len(elem[0])
> >>>>> +
> >>>>> +        src_uri_contents = []
> >>>>> +        with open(src_uri_inc_file, 'w') as f:
> >>>>> +            for module in self.modules_require:
> >>>>> +                # {module_name: (url, version, destdir, fullsrcrev)}
> >>>>> +                repo_url, version, destdir, fullrev = 
> >>>>> self.modules_require[module]
> >>>>> +                if module in self.modules_replace:
> >>>>> +                    actual_module_name, actual_version = 
> >>>>> self.modules_replace[module]
> >>>>> +                else:
> >>>>> +                    actual_module_name, actual_version = (module, 
> >>>>> version)
> >>>>> +                if '://' in repo_url:
> >>>>> +                    repo_url_noprotocol = repo_url.split('://')[1]
> >>>>> +                else:
> >>>>> +                    repo_url_noprotocol = repo_url
> >>>>> +                if not repo_url.startswith('https://'):
> >>>>> +                    repo_url = 'https://' + repo_url
> >>>>> +                name = module.split('/')[-1]
> >>>>> +                if name in srcrev_name_recorded:
> >>>>> +                    name = '-'.join(module.split('/')[-2:])
> >>>>> +                src_uri_contents.append((actual_module_name, 
> >>>>> actual_version, repo_url, fullrev, name, fullrev, repo_url_noprotocol, 
> >>>>> name, actual_module_name))
> >>>>> +                srcrev_name_recorded.append(name)
> >>>>> +            # sort the src_uri_contents and then write it
> >>>>> +            src_uri_contents.sort(key=take_first_len)
> >>>>> +            for content in src_uri_contents:
> >>>>> +                f.write(template % content)
> >>>>> +        logger.info("%s generated" % src_uri_inc_file)
> >>>>> +
> >>>>> +    def gen_relocation_inc(self):
> >>>>> +        """
> >>>>> +        Generate relocation.inc file
> >>>>> +        """
> >>>>> +        relocation_inc_file = os.path.join(self.workdir, 
> >>>>> 'relocation.inc')
> >>>>> +        template = """export sites="%s"
> >>>>> +
> >>>>> +do_compile:prepend() {
> >>>>> +    cd ${S}/src/import
> >>>>> +    for s in $sites; do
> >>>>> +        site_dest=$(echo $s | cut -d: -f1)
> >>>>> +        site_source=$(echo $s | cut -d: -f2)
> >>>>> +        force_flag=$(echo $s | cut -d: -f3)
> >>>>> +        mkdir -p vendor.copy/$site_dest
> >>>>> +        if [ -n "$force_flag" ]; then
> >>>>> +           echo "[INFO] $site_dest: force copying .go files"
> >>>>> +           rm -rf vendor.copy/$site_dest
> >>>>> +           rsync -a --exclude='vendor/' --exclude='.git/' 
> >>>>> vendor.fetch/$site_source/ vendor.copy/$site_dest
> >>>>> +        else
> >>>>> +            [ -n "$(ls -A vendor.copy/$site_dest/*.go 2> /dev/null)" ] 
> >>>>> && { echo "[INFO] vendor.fetch/$site_source -> $site_dest: go copy 
> >>>>> skipped (files present)" ; true ; } || { echo "[INFO] $site_dest: 
> >>>>> copying .go files" ; rsync -a --exclude='vendor/' --exclude='.git/' 
> >>>>> vendor.fetch/$site_source/ vendor.copy/$site_dest ; }
> >>>>> +        fi
> >>>>> +    done
> >>>>> +}
> >>>>> +"""
> >>>>> +        sites = []
> >>>>> +        for module in self.modules_require:
> >>>>> +            # <dest>:<source>[:force]
> >>>>> +            if module in self.modules_srcpaths:
> >>>>> +                srcpath = self.modules_srcpaths[module]
> >>>>> +                logger.debug("Using %s as srcpath of module (%s)" % 
> >>>>> (srcpath, module))
> >>>>> +            else:
> >>>>> +                srcpath = module
> >>>>> +            sites.append("%s:%s:force" % (module, srcpath))
> >>>>> +        # To avoid the former one being overriden by the latter one 
> >>>>> when the former one is a subpath of the latter one, sort sites
> >>>>> +        sites.sort(key=len)
> >>>>> +        with open(relocation_inc_file, 'w') as f:
> >>>>> +            sites_str = ' \\\n           '.join(sites)
> >>>>> +            f.write(template % sites_str)
> >>>>> +        logger.info("%s generated" % relocation_inc_file)
> >>>>> +
> >>>>> +    def gen_modules_txt(self):
> >>>>> +        """
> >>>>> +        Generate modules.txt file
> >>>>> +        """
> >>>>> +        modules_txt_file = os.path.join(self.workdir, 'modules.txt')
> >>>>> +        with open(modules_txt_file, 'w') as f:
> >>>>> +            for l in self.require_lines:
> >>>>> +                f.write('# %s\n' % l)
> >>>>> +                f.write('## explicit\n')
> >>>>> +            for l in self.replace_lines:
> >>>>> +                f.write('# %s\n' %l)
> >>>>> +        logger.info("%s generated" % modules_txt_file)
> >>>>> +
> >>>>> +    def sanity_check(self):
> >>>>> +        """
> >>>>> +        Various anity checks
> >>>>> +        """
> >>>>> +        sanity_check_ok = True
> >>>>> +        #
> >>>>> +        # Sanity Check 1:
> >>>>> +        #     For modules having the same repo, at most one is allowed 
> >>>>> to not have subpath.
> >>>>> +        #     This check operates on self.modules_repoinfo and 
> >>>>> self.modules_subpaths
> >>>>> +        #
> >>>>> +        repo_modules = {}
> >>>>> +        for module in self.modules_repoinfo:
> >>>>> +            # first form {repo: [module1, module2, ...]}
> >>>>> +            repo_url, repo_dest_dir, fullsrcrev = 
> >>>>> self.modules_repoinfo[module]
> >>>>> +            if repo_url not in repo_modules:
> >>>>> +                repo_modules[repo_url] = [module]
> >>>>> +            else:
> >>>>> +                repo_modules[repo_url].append(module)
> >>>>> +        for repo in repo_modules:
> >>>>> +            modules = repo_modules[repo]
> >>>>> +            if len(modules) == 1:
> >>>>> +                continue
> >>>>> +            # for modules sharing the same repo, at most one is 
> >>>>> allowed to not have subpath
> >>>>> +            nosubpath_modules = []
> >>>>> +            for m in modules:
> >>>>> +                if m not in self.modules_subpaths:
> >>>>> +                    nosubpath_modules.append(m)
> >>>>> +            if len(nosubpath_modules) == 0:
> >>>>> +                continue
> >>>>> +            if len(nosubpath_modules) > 1:
> >>>>> +                logger.warning("Multiple modules sharing %s, but they 
> >>>>> don't have subpath: %s. Please double check." % (repo, 
> >>>>> nosubpath_modules))
> >>>>> +            if len(nosubpath_modules) == 1:
> >>>>> +                # do further check, OK if the module is the prefix for 
> >>>>> other modules sharing the same repo
> >>>>> +                module_to_check = nosubpath_modules[0]
> >>>>> +                for m in modules:
> >>>>> +                    if module_to_check == m:
> >>>>> +                        continue
> >>>>> +                    if not m.startswith('%s/' % module_to_check):
> >>>>> +                        logger.warning("%s is sharing repo (%s) with 
> >>>>> other modules, and it might need a subpath. Please double check" % 
> >>>>> (module_to_check, repo))
> >>>>> +                        continue
> >>>>> +
> >>>>> +        #
> >>>>> +        # End of Sanity Check
> >>>>> +        #
> >>>>> +        if not sanity_check_ok:
> >>>>> +            sys.exit(1)
> >>>>> +        return
> >>>>> +
> >>>>> +def main():
> >>>>> +    parser = argparse.ArgumentParser(
> >>>>> +        description="oe-go-mod-autogen.py is used to generate 
> >>>>> src_uri.inc, relocation.inc and modules.txt to be used by go mod 
> >>>>> recipes",
> >>>>> +        epilog="Use %(prog)s --help to get help")
> >>>>> +    parser.add_argument("--repo", help = "Repo for the recipe.", 
> >>>>> required=True)
> >>>>> +    parser.add_argument("--rev", help = "Revision for the recipe.", 
> >>>>> required=True)
> >>>>> +    parser.add_argument("--module", help = "Go module name. To be used 
> >>>>> with '--test'")
> >>>>> +    parser.add_argument("--version", help = "Go module version. To be 
> >>>>> used with '--test'")
> >>>>> +    parser.add_argument("--test", help = "Test to get repo url and 
> >>>>> fullsrcrev, used together with --module and --version.", 
> >>>>> action="store_true")
> >>>>> +    parser.add_argument("--workdir", help = "Working directory to hold 
> >>>>> intermediate results and output.", default=os.getcwd())
> >>>>> +    parser.add_argument("-d", "--debug",
> >>>>> +                        help = "Enable debug output",
> >>>>> +                        action="store_const", const=logging.DEBUG, 
> >>>>> dest="loglevel", default=logging.INFO)
> >>>>> +    parser.add_argument("-q", "--quiet",
> >>>>> +                        help = "Hide all output except error messages",
> >>>>> +                        action="store_const", const=logging.ERROR, 
> >>>>> dest="loglevel")
> >>>>> +    args = parser.parse_args()
> >>>>> +
> >>>>> +    logger.setLevel(args.loglevel)
> >>>>> +    logger.debug("oe-go-mod-autogen.py running for %s:%s in %s" % 
> >>>>> (args.repo, args.rev, args.workdir))
> >>>>> +    gomodtool = GoModTool(args.repo, args.rev, args.workdir)
> >>>>> +    if args.test:
> >>>>> +        if not args.module or not args.version:
> >>>>> +            print("Please specify --module and --version")
> >>>>> +            sys.exit(1)
> >>>>> +        url, srcrev = gomodtool.get_url_srcrev(args.module, 
> >>>>> args.version)
> >>>>> +        print("url = %s, srcrev = %s" % (url, srcrev))
> >>>>> +        if not url or not srcrev:
> >>>>> +            print("Failed to get url & srcrev for %s:%s" % 
> >>>>> (args.module, args.version))
> >>>>> +    else:
> >>>>> +        gomodtool.parse()
> >>>>> +        gomodtool.sanity_check()
> >>>>> +        gomodtool.gen_src_uri_inc()
> >>>>> +        gomodtool.gen_relocation_inc()
> >>>>> +        gomodtool.gen_modules_txt()
> >>>>> +
> >>>>> +
> >>>>> +if __name__ == "__main__":
> >>>>> +    try:
> >>>>> +        ret = main()
> >>>>> +    except Exception as esc:
> >>>>> +        ret = 1
> >>>>> +        import traceback
> >>>>> +        traceback.print_exc()
> >>>>> +    sys.exit(ret)
> >>>>> --
> >>>>> 2.40.0
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>
> >> --
> >> - Thou shalt not follow the NULL pointer, for chaos and madness await
> >> thee at its end
> >> - "Use the force Harry" - Gandalf, Star Trek II
> >>
> >> 
> >>
> >
>


-- 
- Thou shalt not follow the NULL pointer, for chaos and madness await
thee at its end
- "Use the force Harry" - Gandalf, Star Trek II
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#8288): 
https://lists.yoctoproject.org/g/meta-virtualization/message/8288
Mute This Topic: https://lists.yoctoproject.org/mt/101162746/21656
Group Owner: meta-virtualization+ow...@lists.yoctoproject.org
Unsubscribe: 
https://lists.yoctoproject.org/g/meta-virtualization/leave/6693005/21656/1014668956/xyzzy
 [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to