Skip to content
Snippets Groups Projects

gomodtorbm

  • Clone with SSH
  • Clone with HTTPS
  • Embed
  • Share
    The snippet can be accessed without any authentication.
    Authored by Cecylia Bocovich

    Tool for getting snowflake dependencies in the right format for rbm.

    gomodtorbm 5.89 KiB
    #!/usr/bin/env python3
    
    # Usage: go mod graph | ./gomodtorbm
    
    import errno
    import os
    import os.path
    import re
    import sys
    
    STAGING_DIR = "staging"
    
    MAIN_VERSION = "v3.1.41"
    
    # Projects that already exist.
    TERMINALS = {
        "golang.org/x/crypto",
        "golang.org/x/net",
        "golang.org/x/sys",
        "golang.org/x/text",
    }
    
    def strip_version_suffix(import_path):
    	return re.sub(r'/+v[0-9]+$', "", import_path)
    
    def parse_spec(spec):
        print("Parsing "+ spec)
        try:
            import_path, version = spec.split("@")
        except ValueError:
            import_path = spec
            version = MAIN_VERSION
        return strip_version_suffix(import_path), Version(version)
    
    class Version:
        def __init__(self, version):
            self.version = version
    
        def tuple(self):
            m = re.match(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)-(?:0\.)?([0-9]+)-([0-9a-fA-F]+)(\+incompatible)?$', self.version)
            if m:
                g = m.groups()
                return int(g[0]), int(g[1]), int(g[2]), g[3], g[4]
            m = re.match(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)-(rc\.[0-9\.]+)-([0-9a-fA-F]+)$', self.version)
            if m:
                g = m.groups()
                return int(g[0]), int(g[1]), int(g[2]), g[3], g[4]
            m = re.match(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)-(rc\.[0-9]+)$', self.version)
            if m:
                g = m.groups()
                return int(g[0]), int(g[1]), int(g[2]), g[3], ""
            m = re.match(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)-([0-9]{4}\.[0-9]+\.[0-9]+)$', self.version)
            if m:
                g = m.groups()
                return int(g[0]), int(g[1]), int(g[2]), g[3], ""
            m = re.match(r'^v([0-9]+)\.([0-9]+)\.([0-9]+)(\+incompatible)?$', self.version)
            if m:
                g = m.groups()
                return int(g[0]), int(g[1]), int(g[2]), "", ""
            assert False, self.version
    
        def __str__(self):
            major, minor, micro, _, hash = self.tuple()
            if hash:
                if major != 0 or minor != 0 or micro != 0:
                    return "{} # v{}.{}.{}".format(hash, major, minor, micro)
                else:
                    return "{}".format(hash)
            else:
                return "v{}.{}.{}".format(major, minor, micro)
    
        # https://github.com/golang/proposal/blob/master/design/24301-versioned-go.md#update-timing--high-fidelity-builds
        # https://github.com/golang/proposal/blob/master/design/24301-versioned-go.md#compatibility
        def __lt__(self, other):
            return self.tuple() < other.tuple()
    
    PROJECT_MAP = {}
    # Create a unique Project for each unique import path, and set version to the
    # maximum seen.
    def lookup_project(spec):
        import_path, version = parse_spec(spec)
        try:
            project = PROJECT_MAP[import_path]
        except KeyError:
            project = Project(spec)
            PROJECT_MAP[import_path] = project
        print("Project version = ", project.version, "version = ", version)
        if project.version < version:
            project.version = version
        return project
    
    class Project:
        def __init__(self, spec):
            self.import_path, self.version = parse_spec(spec)
            self.deps = set()
    
        def add_dep(self, dep):
            self.deps.add(dep)
    
        # Cheesy heuristics to choose an rbm package name given an import path.
        def project_name(self):
            m = re.match(r'^gopkg\.in/([\w_-]+)\.v[0-9]+$', self.import_path)
            if m:
                return "go" + m.group(1)
            m = re.match(r'^github\.com/(?:golang|hpcloud)/([\w_-]+)$', self.import_path)
            if m:
                return "go" + m.group(1)
    
            try:
                return {
                    "golang.org/x/crypto": "goxcrypto",
                    "golang.org/x/mod": "goxmod",
                    "golang.org/x/net": "goxnet",
                    "golang.org/x/sys": "goxsys",
                    "golang.org/x/sync": "goxsync",
                    "golang.org/x/term": "goxterm",
                    "golang.org/x/text": "goxtext",
                    "golang.org/x/tools": "goxtools",
                    "golang.org/x/xerrors": "goxxerrors",
                    "github.com/pkg/errors": "goerrors",
                    "google.golang.org/protobuf": "protobuf",
                }[self.import_path]
            except KeyError:
                pass
    
            if self.import_path.startswith("github.com/pion"):
                return "-".join(self.import_path.split("/")[1:])
            elif self.import_path.startswith("github.com/"):
                return "-".join(self.import_path.split("/")[2:])
    
            assert False, self.import_path
    
        def output(self, f):
            print("""\
    # vim: filetype=yaml sw=2
    version: '[% c("abbrev") %]'
    git_url: https://{import_path}
    git_hash: {version}
    filename: '[% project %]-[% c("version") %]-[% c("var/osname") %]-[% c("var/build_id") %].tar.gz'
    
    build: '[% c("projects/go/var/build_go_lib") %]'
    
    var:
      container:
        use_container: 1
      go_lib: {import_path}\
    """.format(import_path=self.import_path, version=self.version), file=f)
            if self.deps:
                print("  go_lib_deps:", file=f)
            for dep in sorted(self.deps, key=lambda x: x.project_name()):
                print("    - {project_name}".format(project_name=dep.project_name()), file=f)
            print("""\
    
    input_files:
      - project: container-image
      - name: go
        project: go\
    """, file=f)
            for dep in sorted(self.deps, key=lambda x: x.project_name()):
                print("""\
      - name: {project_name}
        project: {project_name}\
    """.format(project_name=dep.project_name()), file=f)
    
    def makedirs(path):
        try:
            os.makedirs(path)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
    
    for line in sys.stdin:
        mod_spec, req_spec = line.strip().split()
        mod_project = lookup_project(mod_spec)
        req_project = lookup_project(req_spec)
        mod_project.add_dep(req_project)
    
    for project in PROJECT_MAP.values():
        if project.import_path in TERMINALS:
            continue
        project_path = os.path.join(STAGING_DIR, "projects", project.project_name())
        makedirs(project_path)
        with open(os.path.join(project_path, "config"), "w") as f:
            print(project_path)
            project.output(f)
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment