URI: 
       snap: Fix build error: my previous commits did not fix it - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 915202494b140882d594e0542153531f6afada02
   DIR parent b3e4f911f42243bc77b5659e6f9184b349eb5b29
  HTML Author: Anthony Fok <foka@debian.org>
       Date:   Mon, 25 May 2020 03:28:00 -0600
       
       snap: Fix build error: my previous commits did not fix it
       
       - Revert to legacy snap and my custom plugin x-nodejs for now
       - Quote "@babel/cli" and add "@babel/core"
       - Change bin/babel.js to bin/babel
       
       Diffstat:
         A snap/plugins/x-nodejs.yaml          |       8 ++++++++
         A snap/plugins/x_nodejs.py            |     332 +++++++++++++++++++++++++++++++
         M snap/snapcraft.yaml                 |       9 ++++-----
       
       3 files changed, 344 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/snap/plugins/x-nodejs.yaml b/snap/plugins/x-nodejs.yaml
       @@ -0,0 +1,8 @@
       +options:
       +    source:
       +        required: true
       +    source-type:
       +    source-tag:
       +    source-branch:
       +    nodejs-target:
       +        required: true
   DIR diff --git a/snap/plugins/x_nodejs.py b/snap/plugins/x_nodejs.py
       @@ -0,0 +1,332 @@
       +# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
       +#
       +# Modified by Anthony Fok on 2018-10-01 to add support for ppc64el and s390x
       +#
       +# Copyright (C) 2015-2017 Canonical Ltd
       +#
       +# This program is free software: you can redistribute it and/or modify
       +# it under the terms of the GNU General Public License version 3 as
       +# published by the Free Software Foundation.
       +#
       +# This program is distributed in the hope that it will be useful,
       +# but WITHOUT ANY WARRANTY; without even the implied warranty of
       +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       +# GNU General Public License for more details.
       +#
       +# You should have received a copy of the GNU General Public License
       +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
       +
       +"""The nodejs plugin is useful for node/npm based parts.
       +
       +The plugin uses node to install dependencies from `package.json`. It
       +also sets up binaries defined in `package.json` into the `PATH`.
       +
       +This plugin uses the common plugin keywords as well as those for "sources".
       +For more information check the 'plugins' topic for the former and the
       +'sources' topic for the latter.
       +
       +Additionally, this plugin uses the following plugin-specific keywords:
       +
       +    - node-packages:
       +      (list)
       +      A list of dependencies to fetch using npm.
       +    - node-engine:
       +      (string)
       +      The version of nodejs you want the snap to run on.
       +    - npm-run:
       +      (list)
       +      A list of targets to `npm run`.
       +      These targets will be run in order, after `npm install`
       +    - npm-flags:
       +      (list)
       +      A list of flags for npm.
       +    - node-package-manager
       +      (string; default: npm)
       +      The language package manager to use to drive installation
       +      of node packages. Can be either `npm` (default) or `yarn`.
       +"""
       +
       +import collections
       +import contextlib
       +import json
       +import logging
       +import os
       +import shutil
       +import subprocess
       +import sys
       +
       +import snapcraft
       +from snapcraft import sources
       +from snapcraft.file_utils import link_or_copy_tree
       +from snapcraft.internal import errors
       +
       +logger = logging.getLogger(__name__)
       +
       +_NODEJS_BASE = "node-v{version}-linux-{arch}"
       +_NODEJS_VERSION = "8.12.0"
       +_NODEJS_TMPL = "https://nodejs.org/dist/v{version}/{base}.tar.gz"
       +_NODEJS_ARCHES = {"i386": "x86", "amd64": "x64", "armhf": "armv7l", "arm64": "arm64", "ppc64el": "ppc64le", "s390x": "s390x"}
       +_YARN_URL = "https://yarnpkg.com/latest.tar.gz"
       +
       +
       +class NodePlugin(snapcraft.BasePlugin):
       +    @classmethod
       +    def schema(cls):
       +        schema = super().schema()
       +
       +        schema["properties"]["node-packages"] = {
       +            "type": "array",
       +            "minitems": 1,
       +            "uniqueItems": True,
       +            "items": {"type": "string"},
       +            "default": [],
       +        }
       +        schema["properties"]["node-engine"] = {
       +            "type": "string",
       +            "default": _NODEJS_VERSION,
       +        }
       +        schema["properties"]["node-package-manager"] = {
       +            "type": "string",
       +            "default": "npm",
       +            "enum": ["npm", "yarn"],
       +        }
       +        schema["properties"]["npm-run"] = {
       +            "type": "array",
       +            "minitems": 1,
       +            "uniqueItems": False,
       +            "items": {"type": "string"},
       +            "default": [],
       +        }
       +        schema["properties"]["npm-flags"] = {
       +            "type": "array",
       +            "minitems": 1,
       +            "uniqueItems": False,
       +            "items": {"type": "string"},
       +            "default": [],
       +        }
       +
       +        if "required" in schema:
       +            del schema["required"]
       +
       +        return schema
       +
       +    @classmethod
       +    def get_build_properties(cls):
       +        # Inform Snapcraft of the properties associated with building. If these
       +        # change in the YAML Snapcraft will consider the build step dirty.
       +        return ["node-packages", "npm-run", "npm-flags"]
       +
       +    @classmethod
       +    def get_pull_properties(cls):
       +        # Inform Snapcraft of the properties associated with pulling. If these
       +        # change in the YAML Snapcraft will consider the build step dirty.
       +        return ["node-engine", "node-package-manager"]
       +
       +    @property
       +    def _nodejs_tar(self):
       +        if self._nodejs_tar_handle is None:
       +            self._nodejs_tar_handle = sources.Tar(
       +                self._nodejs_release_uri, self._npm_dir
       +            )
       +        return self._nodejs_tar_handle
       +
       +    @property
       +    def _yarn_tar(self):
       +        if self._yarn_tar_handle is None:
       +            self._yarn_tar_handle = sources.Tar(_YARN_URL, self._npm_dir)
       +        return self._yarn_tar_handle
       +
       +    def __init__(self, name, options, project):
       +        super().__init__(name, options, project)
       +        self._source_package_json = os.path.join(
       +            os.path.abspath(self.options.source), "package.json"
       +        )
       +        self._npm_dir = os.path.join(self.partdir, "npm")
       +        self._manifest = collections.OrderedDict()
       +        self._nodejs_release_uri = get_nodejs_release(
       +            self.options.node_engine, self.project.deb_arch
       +        )
       +        self._nodejs_tar_handle = None
       +        self._yarn_tar_handle = None
       +
       +    def pull(self):
       +        super().pull()
       +        os.makedirs(self._npm_dir, exist_ok=True)
       +        self._nodejs_tar.download()
       +        if self.options.node_package_manager == "yarn":
       +            self._yarn_tar.download()
       +        # do the install in the pull phase to download all dependencies.
       +        if self.options.node_package_manager == "npm":
       +            self._npm_install(rootdir=self.sourcedir)
       +        else:
       +            self._yarn_install(rootdir=self.sourcedir)
       +
       +    def clean_pull(self):
       +        super().clean_pull()
       +
       +        # Remove the npm directory (if any)
       +        if os.path.exists(self._npm_dir):
       +            shutil.rmtree(self._npm_dir)
       +
       +    def build(self):
       +        super().build()
       +        if self.options.node_package_manager == "npm":
       +            installed_node_packages = self._npm_install(rootdir=self.builddir)
       +            # Copy the content of the symlink to the build directory
       +            # LP: #1702661
       +            modules_dir = os.path.join(self.installdir, "lib", "node_modules")
       +            _copy_symlinked_content(modules_dir)
       +        else:
       +            installed_node_packages = self._yarn_install(rootdir=self.builddir)
       +            lock_file_path = os.path.join(self.sourcedir, "yarn.lock")
       +            if os.path.isfile(lock_file_path):
       +                with open(lock_file_path) as lock_file:
       +                    self._manifest["yarn-lock-contents"] = lock_file.read()
       +
       +        self._manifest["node-packages"] = [
       +            "{}={}".format(name, installed_node_packages[name])
       +            for name in installed_node_packages
       +        ]
       +
       +    def _npm_install(self, rootdir):
       +        self._nodejs_tar.provision(
       +            self.installdir, clean_target=False, keep_tarball=True
       +        )
       +        npm_cmd = ["npm"] + self.options.npm_flags
       +        npm_install = npm_cmd + ["--cache-min=Infinity", "install"]
       +        for pkg in self.options.node_packages:
       +            self.run(npm_install + ["--global"] + [pkg], cwd=rootdir)
       +        if os.path.exists(os.path.join(rootdir, "package.json")):
       +            self.run(npm_install, cwd=rootdir)
       +            self.run(npm_install + ["--global"], cwd=rootdir)
       +        for target in self.options.npm_run:
       +            self.run(npm_cmd + ["run", target], cwd=rootdir)
       +        return self._get_installed_node_packages("npm", self.installdir)
       +
       +    def _yarn_install(self, rootdir):
       +        self._nodejs_tar.provision(
       +            self.installdir, clean_target=False, keep_tarball=True
       +        )
       +        self._yarn_tar.provision(self._npm_dir, clean_target=False, keep_tarball=True)
       +        yarn_cmd = [os.path.join(self._npm_dir, "bin", "yarn")]
       +        yarn_cmd.extend(self.options.npm_flags)
       +        if "http_proxy" in os.environ:
       +            yarn_cmd.extend(["--proxy", os.environ["http_proxy"]])
       +        if "https_proxy" in os.environ:
       +            yarn_cmd.extend(["--https-proxy", os.environ["https_proxy"]])
       +        flags = []
       +        if rootdir == self.builddir:
       +            yarn_add = yarn_cmd + ["global", "add"]
       +            flags.extend(
       +                [
       +                    "--offline",
       +                    "--prod",
       +                    "--global-folder",
       +                    self.installdir,
       +                    "--prefix",
       +                    self.installdir,
       +                ]
       +            )
       +        else:
       +            yarn_add = yarn_cmd + ["add"]
       +        for pkg in self.options.node_packages:
       +            self.run(yarn_add + [pkg] + flags, cwd=rootdir)
       +
       +        # local packages need to be added as if they were remote, we
       +        # remove the local package.json so `yarn add` doesn't pollute it.
       +        if os.path.exists(self._source_package_json):
       +            with contextlib.suppress(FileNotFoundError):
       +                os.unlink(os.path.join(rootdir, "package.json"))
       +            shutil.copy(
       +                self._source_package_json, os.path.join(rootdir, "package.json")
       +            )
       +            self.run(yarn_add + ["file:{}".format(rootdir)] + flags, cwd=rootdir)
       +
       +        # npm run would require to bring back package.json
       +        if self.options.npm_run and os.path.exists(self._source_package_json):
       +            # The current package.json is the yarn prefilled one.
       +            with contextlib.suppress(FileNotFoundError):
       +                os.unlink(os.path.join(rootdir, "package.json"))
       +            os.link(self._source_package_json, os.path.join(rootdir, "package.json"))
       +        for target in self.options.npm_run:
       +            self.run(
       +                yarn_cmd + ["run", target],
       +                cwd=rootdir,
       +                env=self._build_environment(rootdir),
       +            )
       +        return self._get_installed_node_packages("npm", self.installdir)
       +
       +    def _get_installed_node_packages(self, package_manager, cwd):
       +        try:
       +            output = self.run_output(
       +                [package_manager, "ls", "--global", "--json"], cwd=cwd
       +            )
       +        except subprocess.CalledProcessError as error:
       +            # XXX When dependencies have missing dependencies, an error like
       +            # this is printed to stderr:
       +            # npm ERR! peer dep missing: glob@*, required by glob-promise@3.1.0
       +            # retcode is not 0, which raises an exception.
       +            output = error.output.decode(sys.getfilesystemencoding()).strip()
       +        packages = collections.OrderedDict()
       +        dependencies = json.loads(output, object_pairs_hook=collections.OrderedDict)[
       +            "dependencies"
       +        ]
       +        while dependencies:
       +            key, value = dependencies.popitem(last=False)
       +            # XXX Just as above, dependencies without version are the ones
       +            # missing.
       +            if "version" in value:
       +                packages[key] = value["version"]
       +            if "dependencies" in value:
       +                dependencies.update(value["dependencies"])
       +        return packages
       +
       +    def get_manifest(self):
       +        return self._manifest
       +
       +    def _build_environment(self, rootdir):
       +        env = os.environ.copy()
       +        if rootdir.endswith("src"):
       +            hidden_path = os.path.join(rootdir, "node_modules", ".bin")
       +            if env.get("PATH"):
       +                new_path = "{}:{}".format(hidden_path, env.get("PATH"))
       +            else:
       +                new_path = hidden_path
       +            env["PATH"] = new_path
       +        return env
       +
       +
       +def _get_nodejs_base(node_engine, machine):
       +    if machine not in _NODEJS_ARCHES:
       +        raise errors.SnapcraftEnvironmentError(
       +            "architecture not supported ({})".format(machine)
       +        )
       +    return _NODEJS_BASE.format(version=node_engine, arch=_NODEJS_ARCHES[machine])
       +
       +
       +def get_nodejs_release(node_engine, arch):
       +    return _NODEJS_TMPL.format(
       +        version=node_engine, base=_get_nodejs_base(node_engine, arch)
       +    )
       +
       +
       +def _copy_symlinked_content(modules_dir):
       +    """Copy symlinked content.
       +
       +    When running newer versions of npm, symlinks to the local tree are
       +    created from the part's installdir to the root of the builddir of the
       +    part (this only affects some build configurations in some projects)
       +    which is valid when running from the context of the part but invalid
       +    as soon as the artifacts migrate across the steps,
       +    i.e.; stage and prime.
       +
       +    If modules_dir does not exist we simply return.
       +    """
       +    if not os.path.exists(modules_dir):
       +        return
       +    modules = [os.path.join(modules_dir, d) for d in os.listdir(modules_dir)]
       +    symlinks = [l for l in modules if os.path.islink(l)]
       +    for link_path in symlinks:
       +        link_target = os.path.realpath(link_path)
       +        os.unlink(link_path)
       +        link_or_copy_tree(link_target, link_path)
   DIR diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
       @@ -1,5 +1,4 @@
        name: hugo
       -base: core
        version: "0.72.0-DEV"
        summary: Fast and Flexible Static Site Generator
        description: |
       @@ -8,7 +7,6 @@ description: |
          with content and templates and renders them into a full HTML website.
        confinement: strict
        grade: devel # "devel" or "stable"
       -license: Apache-2.0
        
        apps:
          hugo:
       @@ -68,10 +66,11 @@ parts:
              ls -l $SNAPCRAFT_PART_INSTALL/bin/hugo
        
          node:
       -    plugin: nodejs
       +    plugin: x-nodejs
            node-packages:
       -        - postcss-cli
                - "@babel/cli"
       +        - "@babel/core"
       +        - postcss-cli
            filesets:
              node:
                - bin/node
       @@ -79,7 +78,7 @@ parts:
                - bin/postcss
                - lib/node_modules/postcss-cli/*
              babel:
       -        - bin/babel.js
       +        - bin/babel
                - lib/node_modules/@babel/cli/*
            prime:
              - $node