github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/snap/plugins/x-dep.py (about)

     1  # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
     2  #
     3  # Copyright (C) 2018 Canonical Ltd
     4  #
     5  # This program is free software: you can redistribute it and/or modify
     6  # it under the terms of the GNU General Public License version 3 as
     7  # published by the Free Software Foundation.
     8  #
     9  # This program is distributed in the hope that it will be useful,
    10  # but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  # GNU General Public License for more details.
    13  #
    14  # You should have received a copy of the GNU General Public License
    15  # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  """The dep plugin can be used for dep-enabled go projects.
    18  
    19  This plugin uses the common plugin keywords as well as those for "sources".
    20  For more information check the 'plugins' topic for the former and the
    21  'sources' topic for the latter.
    22  
    23  Additionally, this plugin uses the following plugin-specific keywords:
    24  
    25      - go-packages:
    26        (list of strings)
    27        Go packages to build/install, these must be a "main" package.
    28        Dependencies should have already been retrieved.
    29        Packages that are not "main" will not cause an error, but would
    30        not be useful either.
    31  
    32      - go-importpath:
    33        (string)
    34        This entry tells the checked out `source` to live within a certain path
    35        within `GOPATH`. This is required in order to work with absolute imports
    36        and import path checking.
    37  """
    38  
    39  import logging
    40  import os
    41  import shutil
    42  
    43  import snapcraft
    44  from snapcraft import common
    45  
    46  
    47  logger = logging.getLogger(__name__)
    48  
    49  
    50  class DepPlugin(snapcraft.BasePlugin):
    51      @classmethod
    52      def schema(cls):
    53          schema = super().schema()
    54          schema["properties"]["go-importpath"] = {"type": "string"}
    55          schema["properties"]["go-packages"] = {
    56              "type": "array",
    57              "minitems": 1,
    58              "uniqueItems": True,
    59              "items": {"type": "string"},
    60              "default": [],
    61          }
    62  
    63          # The import path must be specified.
    64          schema["required"].append("go-importpath")
    65  
    66          return schema
    67  
    68      @classmethod
    69      def get_build_properties(cls):
    70          # Inform Snapcraft of the properties associated with building. If these
    71          # change in the YAML Snapcraft will consider the build step dirty.
    72          return ["go-packages"]
    73  
    74      @classmethod
    75      def get_pull_properties(cls):
    76          # Inform Snapcraft of the properties associated with pulling. If these
    77          # change in the YAML Snapcraft will consider the pull step dirty.
    78          return ["go-importpath"]
    79  
    80      def __init__(self, name, options, project):
    81          super().__init__(name, options, project)
    82          self.build_packages.extend(["golang-go", "git"])
    83          self._gopath = os.path.join(self.partdir, "go")
    84          self._gopath_src = os.path.join(self._gopath, "src")
    85          self._gopath_bin = os.path.join(self._gopath, "bin")
    86          self._gopath_pkg = os.path.join(self._gopath, "pkg")
    87          self._path_in_gopath = os.path.join(self._gopath_src, self.options.go_importpath)
    88  
    89      def pull(self):
    90          super().pull()
    91  
    92          try:
    93              shutil.rmtree(os.path.dirname(self._path_in_gopath))
    94          except:  # noqa: E722
    95              pass
    96          finally:
    97              os.makedirs(os.path.dirname(self._path_in_gopath), exist_ok=True)
    98  
    99          shutil.copytree(self.sourcedir, self._path_in_gopath, symlinks=True, ignore_dangling_symlinks=True)
   100  
   101          # Fetch and run dep
   102          logger.info("Fetching dep...")
   103          self._run(["go", "get", "github.com/golang/dep/cmd/dep"])
   104  
   105          logger.info("Obtaining project dependencies...")
   106          self._run(
   107              [
   108                  "dep",
   109                  "ensure",
   110                  "-vendor-only",
   111              ]
   112          )
   113  
   114      def clean_pull(self):
   115          super().clean_pull()
   116  
   117          # Remove the gopath (if present)
   118          if os.path.exists(self._gopath):
   119              shutil.rmtree(self._gopath)
   120  
   121      def build(self):
   122          super().build()
   123  
   124          for go_package in self.options.go_packages:
   125              self._run(["go", "install", go_package])
   126          if not self.options.go_packages:
   127              self._run(["go", "install", "./{}/...".format(self.options.go_importpath)])
   128  
   129          install_bin_path = os.path.join(self.installdir, "bin")
   130          os.makedirs(install_bin_path, exist_ok=True)
   131          os.makedirs(self._gopath_bin, exist_ok=True)
   132          for binary in os.listdir(self._gopath_bin):
   133              # Skip dep. It serves no purpose in production.
   134              if binary == "dep":
   135                  continue
   136  
   137              binary_path = os.path.join(self._gopath_bin, binary)
   138              shutil.copy2(binary_path, install_bin_path)
   139  
   140      def clean_build(self):
   141          super().clean_build()
   142  
   143          if os.path.isdir(self._gopath_bin):
   144              shutil.rmtree(self._gopath_bin)
   145  
   146          if os.path.isdir(self._gopath_pkg):
   147              shutil.rmtree(self._gopath_pkg)
   148  
   149      def _run(self, cmd, **kwargs):
   150          env = self._build_environment()
   151          return self.run(cmd, cwd=self._path_in_gopath, env=env, **kwargs)
   152  
   153      def _build_environment(self):
   154          env = os.environ.copy()
   155          env["GOPATH"] = self._gopath
   156          env["GOBIN"] = self._gopath_bin
   157  
   158          # Add $GOPATH/bin so dep is actually callable.
   159          env["PATH"] = "{}:{}".format(
   160              os.path.join(self._gopath, "bin"), env.get("PATH", "")
   161          )
   162  
   163          include_paths = []
   164          for root in [self.installdir, self.project.stage_dir]:
   165              include_paths.extend(
   166                  common.get_library_paths(root, self.project.arch_triplet)
   167              )
   168  
   169          flags = common.combine_paths(include_paths, "-L", " ")
   170          env["CGO_LDFLAGS"] = "{} {} {}".format(
   171              env.get("CGO_LDFLAGS", ""), flags, env.get("LDFLAGS", "")
   172          )
   173  
   174          return env