Remove duplicated scripts (#833)
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"core": "Add onDidEnterIdle to MapObserver, which fires whenever render completes and no repaint is scheduled.",
|
||||
"darwin": "Add mapViewDidEnterIdle to MGLMapViewDelegate, which fires whenever render completes and no repaint is scheduled.",
|
||||
"android": "Add onDidEnterIdle listener to MapView, which fires whenever render completes and no repaint is scheduled.",
|
||||
"issue": 13469
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"core": "Add `--includeIdeographs` option to mbgl-offline tool to include CJK glyphs in offline region, at the cost of increased size requirements.",
|
||||
"darwin": "Added the `MGLOfflineRegion.includesIdeographicGlyphs` property, which you can set to NO to exclude CJK glyphs and save space.",
|
||||
"android": "Added the `includeIdeographs` property to `OfflineRegionDefinition`, which you can set to false to exclude CJK glyphs and save space.",
|
||||
"issue": 11561
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"core": "Fix OverscaledTileID::isChildOf to exclude tiles with different wrap. Incorrect child detection could cause flickering for symbols displaying in two wrapped world copies at the same time.",
|
||||
"issue": 13478
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
console.log("DISABLED — https://github.com/mapbox/mapbox-gl-native-ios/issues/19")
|
||||
process.exit(0)
|
||||
|
||||
/*
|
||||
This script takes two parameters or three environment variables:
|
||||
|
||||
{CI job name|$CIRCLE_JOB} {SHA1...SHA1|$CIRCLE_MERGE_BASE...$CIRCLE_SHA1}
|
||||
|
||||
The flow of this script:
|
||||
|
||||
- List of files changed in PR: `git diff --name-only start...end`
|
||||
- Extract list into array.
|
||||
- Remove items from array if they match:
|
||||
- Global ignore list.
|
||||
- Other platform ignore lists.
|
||||
- If array still contains items, do not authorize skipping CI job.
|
||||
- Else if array is empty, skip CI job.
|
||||
|
||||
To add support for a new platform:
|
||||
|
||||
- Add a new PLATFORM_FILES array with a list of unique paths for the
|
||||
files belonging to the platform.
|
||||
- Add a case to `skippableFilePatternsForCIJob()` with:
|
||||
- The prefix for the platform's CI job names.
|
||||
- A concatenated array of other platform paths that are safe to ignore
|
||||
for the new platform. These should be files that can change without
|
||||
having any effect on the output of the new platform.
|
||||
- Update other cases in `skippableFilePatternsForCIJob()` to include the
|
||||
paths for the new platform.
|
||||
*/
|
||||
|
||||
const execSync = require('child_process').execSync;
|
||||
const _ = require('lodash');
|
||||
const minimatch = require("minimatch");
|
||||
|
||||
console.step = _.partial(console.log, '\n\033[1m\033[36m*', _, '\033[0m');
|
||||
|
||||
// BUILD PARAMETERS
|
||||
const CI_JOB_NAME = process.argv[2] || process.env.CIRCLE_JOB;
|
||||
if (!CI_JOB_NAME) { console.error('You must specify the name of a CI job as a parameter or environment variable.'); process.exit(1); }
|
||||
|
||||
const COMMIT_RANGE = process.argv[3] || `${process.env.CIRCLE_MERGE_BASE}...${process.env.CIRCLE_SHA1}`;
|
||||
if (!COMMIT_RANGE || COMMIT_RANGE.includes('undefined')) { console.error('You must specify a range of commits to check for changed files in as a parameter or environment variable.'); process.exit(1); }
|
||||
|
||||
// FILE SKIPPING PATTERNS
|
||||
const ALWAYS_SKIPPABLE_FILES = [
|
||||
'**/CHANGELOG.md',
|
||||
'**/README.md',
|
||||
'**/CONTRIBUTING.md',
|
||||
'**/DEVELOPING.md',
|
||||
'**/INSTALL.md',
|
||||
'**/*.podspec'
|
||||
]
|
||||
|
||||
const ANDROID_FILES = [
|
||||
'platform/android/**'
|
||||
]
|
||||
|
||||
const DARWIN_FILES = [
|
||||
'platform/darwin/**'
|
||||
]
|
||||
|
||||
const IOS_FILES = [
|
||||
'platform/ios/**'
|
||||
]
|
||||
|
||||
const MACOS_FILES = [
|
||||
'platform/macos/**'
|
||||
]
|
||||
|
||||
const OTHER_PLATFORMS = [
|
||||
'platform/glfw/**',
|
||||
'platform/linux/**',
|
||||
'platform/node/**',
|
||||
'platform/qt/**',
|
||||
'benchmark/**',
|
||||
'test/**'
|
||||
]
|
||||
|
||||
function skippableFilePatternsForCIJob(job) {
|
||||
if (job.includes('render-tests')) {
|
||||
// Render tests run on specific platforms are effectively unskippable core jobs, not platform jobs.
|
||||
return ALWAYS_SKIPPABLE_FILES;
|
||||
} else if (job.startsWith('ios')) {
|
||||
return _.concat(ALWAYS_SKIPPABLE_FILES, ANDROID_FILES, MACOS_FILES, OTHER_PLATFORMS);
|
||||
} else if (job.startsWith('android')) {
|
||||
return _.concat(ALWAYS_SKIPPABLE_FILES, DARWIN_FILES, IOS_FILES, MACOS_FILES, OTHER_PLATFORMS);
|
||||
} else if (job.startsWith('macos')) {
|
||||
return _.concat(ALWAYS_SKIPPABLE_FILES, ANDROID_FILES, IOS_FILES, OTHER_PLATFORMS);
|
||||
} else {
|
||||
return ALWAYS_SKIPPABLE_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
console.step(`Getting list of files changed between ${COMMIT_RANGE}`);
|
||||
|
||||
let changedFiles = execSync(`git diff --name-only ${COMMIT_RANGE}`).toString().split('\n');
|
||||
changedFiles = _.compact(changedFiles);
|
||||
|
||||
console.log(`${changedFiles.length} file${changedFiles.length == 1 ? '':'s'} changed.`);
|
||||
|
||||
console.step(`Checking changed files for paths relevant to ${CI_JOB_NAME} job`);
|
||||
|
||||
// Filter the changed files array to remove files that are irrelevant to the specified CI job.
|
||||
_.remove(changedFiles, function(changedFile) {
|
||||
for (const skippableFilePattern of skippableFilePatternsForCIJob(CI_JOB_NAME)) {
|
||||
if (minimatch(changedFile, skippableFilePattern, { dot: true, nocase: true })) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (changedFiles.length) {
|
||||
console.log(`Found ${changedFiles.length} unskippable changed file${changedFiles.length == 1 ? '':'s'}:\n`, changedFiles);
|
||||
} else {
|
||||
console.log(`Found no relevant changed files, so it's safe to skip the remainder of this CI job.`)
|
||||
if (process.env.CIRCLECI) {
|
||||
console.step('Aborting CI job');
|
||||
execSync(`circleci step halt`, {stdio: 'inherit'});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if [ ! $(command -v qmake 2> /dev/null) ]; then
|
||||
echo "No qmake found - missing Qt development files"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,7 +0,0 @@
|
||||
param([string]$file, [string]$hash);
|
||||
|
||||
$hashFromFile = Get-FileHash -Path $file -Algorithm SHA256
|
||||
|
||||
if ($hashFromFile.Hash -ne $hash) {
|
||||
Throw 'Hash mismatch!'
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const github = require('@octokit/rest').plugin(require('@octokit/plugin-retry'))({
|
||||
retry: { doNotRetry: [ /* Empty — retry on any error code. */ ] }
|
||||
})
|
||||
const prettyBytes = require('pretty-bytes');
|
||||
const fs = require('fs');
|
||||
|
||||
const SIZE_CHECK_APP_ID = 14028;
|
||||
const SIZE_CHECK_APP_INSTALLATION_ID = 229425;
|
||||
|
||||
const file = process.argv[2];
|
||||
const label = process.argv[3];
|
||||
const {size} = fs.statSync(file);
|
||||
const name = `Size - ${label}`;
|
||||
|
||||
process.on('unhandledRejection', error => {
|
||||
console.log(error);
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY'];
|
||||
if (!pk) {
|
||||
console.log('Fork PR; not computing size.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const key = Buffer.from(pk, 'base64').toString('binary');
|
||||
const payload = {
|
||||
exp: Math.floor(Date.now() / 1000) + 60,
|
||||
iat: Math.floor(Date.now() / 1000),
|
||||
iss: SIZE_CHECK_APP_ID
|
||||
};
|
||||
|
||||
const token = jwt.sign(payload, key, {algorithm: 'RS256'});
|
||||
github.authenticate({type: 'app', token});
|
||||
|
||||
function getPriorSize() {
|
||||
const mergeBase = process.env['CIRCLE_MERGE_BASE'];
|
||||
if (!mergeBase) {
|
||||
console.log('No merge base available.');
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return github.checks.listForRef({
|
||||
owner: 'mapbox',
|
||||
repo: 'mapbox-gl-native',
|
||||
ref: mergeBase
|
||||
}).then(({data}) => {
|
||||
const run = data.check_runs.find(run => run.name === name);
|
||||
if (!run) {
|
||||
console.log('No matching check found.');
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return +run.output.summary.match(/`.*` is (\d+) bytes/)[1];
|
||||
});
|
||||
}
|
||||
|
||||
github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATION_ID})
|
||||
.then(({data}) => {
|
||||
github.authenticate({type: 'token', token: data.token});
|
||||
getPriorSize().then(prior => {
|
||||
const title = (() => {
|
||||
if (prior) {
|
||||
const change = size - prior;
|
||||
const percent = (change / prior) * 100;
|
||||
return `${change >= 0 ? '+' : ''}${prettyBytes(change)} ${percent.toFixed(3)}% (${prettyBytes(size)})`;
|
||||
} else {
|
||||
return prettyBytes(size);
|
||||
}
|
||||
})();
|
||||
|
||||
console.log(`${label}: ${title} (${size} bytes)`);
|
||||
|
||||
return github.checks.create({
|
||||
owner: 'mapbox',
|
||||
repo: 'mapbox-gl-native',
|
||||
name: `Size - ${label}`,
|
||||
head_branch: process.env['CIRCLE_BRANCH'],
|
||||
head_sha: process.env['CIRCLE_SHA1'],
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
completed_at: new Date().toISOString(),
|
||||
output: {
|
||||
title,
|
||||
summary: `\`${file}\` is ${size} bytes (${prettyBytes(size)})`
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -1,110 +0,0 @@
|
||||
FROM ubuntu:disco-20190718
|
||||
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
ENV ANDROID_HOME="/opt/android"
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# Use faster mirrors from Finland
|
||||
COPY etc/apt/sources.list /etc/apt
|
||||
|
||||
RUN set -eu \
|
||||
&& apt-get update\
|
||||
&& apt-get dist-upgrade -y
|
||||
|
||||
# CI requirements
|
||||
RUN set -eu && apt-get install -y \
|
||||
ca-certificates \
|
||||
git \
|
||||
gzip \
|
||||
ssh \
|
||||
tar
|
||||
|
||||
# Base dependencies
|
||||
RUN set -eu && apt-get install -y \
|
||||
ccache \
|
||||
clang-8 \
|
||||
clang-format-8 \
|
||||
clang-tidy-8 \
|
||||
cmake \
|
||||
fonts-noto \
|
||||
g++-8 \
|
||||
libc++-8-dev \
|
||||
libc++abi-8-dev \
|
||||
mesa-common-dev \
|
||||
ninja-build \
|
||||
nodejs \
|
||||
npm \
|
||||
pkg-config \
|
||||
python3-pip \
|
||||
software-properties-common \
|
||||
xvfb
|
||||
|
||||
RUN pip3 install cmake_format
|
||||
|
||||
# Linux dependencies
|
||||
RUN set -eu && apt-get install -y \
|
||||
libcurl4-openssl-dev \
|
||||
libgl1-mesa-dev \
|
||||
libglfw3-dev \
|
||||
libicu-dev \
|
||||
libjpeg-turbo8-dev \
|
||||
libpng-dev \
|
||||
libuv1-dev \
|
||||
zlib1g-dev
|
||||
|
||||
# Qt dependencies
|
||||
RUN set -eu && apt-get install -y \
|
||||
qdoc-qt5 \
|
||||
qt5-default
|
||||
|
||||
# Android dependencies
|
||||
RUN set -eu && apt-get install -y \
|
||||
coreutils \
|
||||
curl \
|
||||
openjdk-8-jdk-headless \
|
||||
unzip
|
||||
|
||||
# Install old compilers
|
||||
RUN set -eu \
|
||||
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1E9377A2BA9EF27F \
|
||||
&& add-apt-repository "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" \
|
||||
&& add-apt-repository "deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe" \
|
||||
&& apt-get install -y \
|
||||
g++-4.9 \
|
||||
g++-5
|
||||
|
||||
# Install Android NDK
|
||||
RUN set -eu \
|
||||
&& mkdir -p ${ANDROID_HOME} && cd ${ANDROID_HOME} \
|
||||
&& curl -L --retry 3 https://dl.google.com/android/repository/android-ndk-r19-linux-x86_64.zip -o ndk.zip \
|
||||
&& (echo "f02ad84cb5b6e1ff3eea9e6168037c823408c8ac ndk.zip" | sha1sum -c) \
|
||||
&& unzip -q ndk.zip && rm ndk.zip && mv android-ndk-r* ndk-bundle
|
||||
|
||||
|
||||
RUN set -eu \
|
||||
&& cd ${ANDROID_HOME} \
|
||||
&& curl -L --retry 3 https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -o tools.zip \
|
||||
&& (echo "92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9 tools.zip" | sha256sum -c) \
|
||||
&& unzip -q tools.zip && rm tools.zip
|
||||
|
||||
RUN set -eu \
|
||||
&& yes | ${ANDROID_HOME}/tools/bin/sdkmanager \
|
||||
"platform-tools" \
|
||||
"platforms;android-26" \
|
||||
"build-tools;26.0.3" \
|
||||
"platforms;android-27" \
|
||||
"build-tools;27.0.3" \
|
||||
"platforms;android-28" \
|
||||
"build-tools;28.0.3" \
|
||||
"extras;android;m2repository" \
|
||||
"patcher;v4" \
|
||||
"extras;google;m2repository" \
|
||||
"extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2" \
|
||||
"cmake;3.10.2.4988404"
|
||||
|
||||
# Configure ccache
|
||||
RUN set -eu && /usr/sbin/update-ccache-symlinks
|
||||
|
||||
# Cleanup
|
||||
RUN set -eu && apt-get clean
|
||||
@@ -1,10 +0,0 @@
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco main restricted
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco-updates main restricted
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco universe
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco-updates universe
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco multiverse
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco-updates multiverse
|
||||
deb http://fi.archive.ubuntu.com/ubuntu/ disco-backports main restricted universe multiverse
|
||||
deb http://security.ubuntu.com/ubuntu/ disco-security main restricted
|
||||
deb http://security.ubuntu.com/ubuntu/ disco-security universe
|
||||
deb http://security.ubuntu.com/ubuntu/ disco-security multiverse
|
||||
@@ -1,201 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
r"""
|
||||
ClangTidy Diff Checker
|
||||
======================
|
||||
|
||||
This script reads input from a unified diff, runs clang-tidy on all changed
|
||||
files and outputs clang-tidy warnings in changed lines only. This is useful to
|
||||
detect clang-tidy regressions in the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 HEAD^ | clang-tidy-diff.py -p1
|
||||
svn diff --diff-cmd=diff -x-U0 | \
|
||||
clang-tidy-diff.py -fix -checks=-*,modernize-use-override
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import multiprocessing
|
||||
import os
|
||||
import threading
|
||||
|
||||
is_py2 = sys.version[0] == '2'
|
||||
|
||||
if is_py2:
|
||||
import Queue as queue
|
||||
else:
|
||||
import queue as queue
|
||||
|
||||
def run_tidy(command, lines_by_file, queue, failed_files):
|
||||
"""Takes filenames out of queue and runs clang-tidy on them."""
|
||||
while True:
|
||||
name = queue.get()
|
||||
|
||||
line_filter_json = json.dumps([{"name" : name, "lines" : lines_by_file[name]}], separators = (',', ':'))
|
||||
if sys.platform == 'win32':
|
||||
line_filter_json = re.sub(r'"', r'"""', line_filter_json)
|
||||
else:
|
||||
line_filter_json = "'" + line_filter_json + "'";
|
||||
|
||||
invocation = list(command)
|
||||
invocation.append('-line-filter=' + line_filter_json)
|
||||
invocation.append(name)
|
||||
|
||||
sys.stdout.write('Checking differences in {}...\n'.format(name))
|
||||
return_code = subprocess.call(' '.join(invocation), shell=True)
|
||||
if return_code != 0:
|
||||
failed_files.append(name)
|
||||
queue.task_done()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=
|
||||
'Run clang-tidy against changed files, and '
|
||||
'output diagnostics only for modified '
|
||||
'lines.')
|
||||
parser.add_argument('-clang-tidy-binary', metavar='PATH',
|
||||
default='clang-tidy',
|
||||
help='path to clang-tidy binary')
|
||||
parser.add_argument('-p', metavar='NUM', default=0,
|
||||
help='strip the smallest prefix containing P slashes')
|
||||
parser.add_argument('-regex', metavar='PATTERN', default=None,
|
||||
help='custom pattern selecting file paths to check '
|
||||
'(case sensitive, overrides -iregex)')
|
||||
parser.add_argument('-iregex', metavar='PATTERN', default=
|
||||
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
|
||||
help='custom pattern selecting file paths to check '
|
||||
'(case insensitive, overridden by -regex)')
|
||||
|
||||
parser.add_argument('-fix', action='store_true', default=False,
|
||||
help='apply suggested fixes')
|
||||
parser.add_argument('-checks',
|
||||
help='checks filter, when not specified, use clang-tidy '
|
||||
'default',
|
||||
default='')
|
||||
parser.add_argument('-path', dest='build_path',
|
||||
help='Path used to read a compile command database.')
|
||||
parser.add_argument('-extra-arg', dest='extra_arg',
|
||||
action='append', default=[],
|
||||
help='Additional argument to append to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-extra-arg-before', dest='extra_arg_before',
|
||||
action='append', default=[],
|
||||
help='Additional argument to prepend to the compiler '
|
||||
'command line.')
|
||||
parser.add_argument('-j', type=int, default=0,
|
||||
help='number of tidy instances to be run in parallel.')
|
||||
parser.add_argument('-quiet', action='store_true', default=False,
|
||||
help='Run clang-tidy in quiet mode')
|
||||
clang_tidy_args = []
|
||||
argv = sys.argv[1:]
|
||||
if '--' in argv:
|
||||
clang_tidy_args.extend(argv[argv.index('--'):])
|
||||
argv = argv[:argv.index('--')]
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename == None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match('^%s$' % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
continue
|
||||
end_line = start_line + line_count - 1;
|
||||
lines_by_file.setdefault(filename, []).append([start_line, end_line])
|
||||
|
||||
if len(lines_by_file) == 0:
|
||||
print("No relevant changes found.")
|
||||
sys.exit(0)
|
||||
|
||||
# Run clang-tidy on files containing changes.
|
||||
command = [args.clang_tidy_binary]
|
||||
if args.fix:
|
||||
command.append('-fix')
|
||||
if args.checks != '':
|
||||
command.append('-checks=' + quote + args.checks + quote)
|
||||
if args.quiet:
|
||||
command.append('-quiet')
|
||||
if args.build_path is not None:
|
||||
command.append('-p=%s' % args.build_path)
|
||||
for arg in args.extra_arg:
|
||||
command.append('-extra-arg=%s' % arg)
|
||||
for arg in args.extra_arg_before:
|
||||
command.append('-extra-arg-before=%s' % arg)
|
||||
command.extend(clang_tidy_args)
|
||||
|
||||
try:
|
||||
invocation = list(command)
|
||||
invocation.append('-')
|
||||
subprocess.check_call(invocation)
|
||||
except:
|
||||
print("Unable to run clang-tidy: {}".format(' '.join(command)))
|
||||
sys.exit(1)
|
||||
|
||||
max_task = args.j
|
||||
if max_task == 0:
|
||||
max_task = multiprocessing.cpu_count()
|
||||
|
||||
return_code = 0
|
||||
try:
|
||||
# Spin up a bunch of tidy-launching threads.
|
||||
task_queue = queue.Queue(max_task)
|
||||
# List of files with a non-zero return code.
|
||||
failed_files = []
|
||||
for _ in range(max_task):
|
||||
t = threading.Thread(target=run_tidy,
|
||||
args=(command, lines_by_file, task_queue, failed_files))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
# Fill the queue with files.
|
||||
for name in lines_by_file:
|
||||
task_queue.put(name)
|
||||
|
||||
# Wait for all threads to be done.
|
||||
task_queue.join()
|
||||
if len(failed_files):
|
||||
return_code = 1
|
||||
|
||||
except KeyboardInterrupt:
|
||||
# This is a sad hack. Unfortunately subprocess goes
|
||||
# bonkers with ctrl-c and we start forking merrily.
|
||||
print('\nCtrl-C detected, goodbye.')
|
||||
os.kill(0, 9)
|
||||
return_code = 1
|
||||
|
||||
sys.exit(return_code)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CLANG_TIDY_PREFIX=${CLANG_TIDY_PREFIX:-$(scripts/mason.sh PREFIX clang-tidy VERSION 7.0.0)}
|
||||
CLANG_TIDY=${CLANG_TIDY_PREFIX}/bin/clang-tidy
|
||||
CLANG_APPLY=${CLANG_TIDY_PREFIX}/bin/clang-apply-replacements
|
||||
|
||||
for CLANG_FILE in "${CLANG_TIDY}" "${CLANG_APPLY}"; do
|
||||
command -v "${CLANG_FILE}" > /dev/null 2>&1 || {
|
||||
echo "Can't find ${CLANG_FILE} in PATH."
|
||||
if [ -z "${CLANG_FILE}" ]; then
|
||||
echo "Alternatively, you can manually set ${!CLANG_FILE@}."
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
echo "Running Clang checks... (this might take a while)"
|
||||
|
||||
if [[ -n ${3:-} ]] && [[ ${3:-} == "--diff" ]]; then
|
||||
git diff "origin/$2" | "scripts/clang-tidy-diff.py" \
|
||||
-clang-tidy-binary "${CLANG_TIDY}" \
|
||||
-p 1 -quiet -path "$1"
|
||||
else
|
||||
git ls-files "src/*.cpp" "test/*.cpp" "platform/*.cpp" "bin/*.cpp" | \
|
||||
xargs "${CLANG_TIDY_PREFIX}/share/run-clang-tidy.py" \
|
||||
-clang-tidy-binary "${CLANG_TIDY}" \
|
||||
-clang-apply-replacements-binary "${CLANG_APPLY}" \
|
||||
-quiet -p "$1" -fix
|
||||
fi
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
#
|
||||
# This script takes three values: $1 should be a decimal value reflecting the
|
||||
# percentage of lines covered, with a maximum value of 100.0, $2 is
|
||||
# the platform the percentage pertains to (iOS or Android), and $3 is the
|
||||
# test scheme being run (on iOS, this is currently CI).
|
||||
#
|
||||
|
||||
# Check that platform input values are valid.
|
||||
|
||||
if [[ ! $2 = "iOS" && ! $2 = "Android" ]]; then
|
||||
echo "$2 does not match either 'iOS' or 'Android'. Platform must be specified for coverage report."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
circle_sha=""
|
||||
if [[ $CIRCLE_SHA1 ]]; then
|
||||
circle_sha="$CIRCLE_SHA1"
|
||||
fi
|
||||
# Create a formatted JSON file that contains the current coverage.
|
||||
|
||||
current_date=$(TZ=UTC date +"%FT%T%z")
|
||||
file_name=$2_coverage.json
|
||||
cat <<EOF > $file_name
|
||||
{"code_coverage":$1,"platform":"$2","sdk":"Maps","scheme":"$3","created_at":"$current_date","sha":"$circle_sha"}
|
||||
EOF
|
||||
gzip -f $file_name
|
||||
|
||||
if [ -z `which aws` ]; then
|
||||
brew install awscli
|
||||
fi
|
||||
|
||||
aws s3 cp $file_name.gz s3://mapbox-loading-dock/raw/mobile.codecoverage/$current_date/
|
||||
echo $
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Treats all characters as bytes, removes Unicode awareness from (broken?) macOS sed.
|
||||
export LC_ALL=C
|
||||
|
||||
if [ `uname -s` = 'Darwin' ]; then
|
||||
# BSD sed accepts a file extension.
|
||||
SED="sed -i''"
|
||||
else
|
||||
# GNU sed does not.
|
||||
SED="sed -i"
|
||||
fi
|
||||
|
||||
# Gather list of files
|
||||
FILES=$(git ls-files "*.hpp" "*.cpp" "*.h" "*.mm" "*.m" "*.c" "*.java" "*.xml" "*.ejs" "*.gradle" |
|
||||
sed '/^platform\/android\/MapboxGLAndroidSDK\/src\/main\/java\/com\/almeros\// d;/^src\/clipper\// d;/^platform\/ios\/uitest\/OCMock/d')
|
||||
|
||||
# Adds trailing newlines to files.
|
||||
echo "Checking for missing trailing newlines..."
|
||||
echo "${FILES}" | tr '\n' '\0' | xargs -0 ${SED} -e '$a\'
|
||||
|
||||
# Removes trailing whitespace.
|
||||
echo "Checking for trailing whitespace..."
|
||||
echo "${FILES}" | tr '\n' '\0' | xargs -0 ${SED} 's/ *$// '
|
||||
|
||||
# Add space after // comments. Does not replace // within double quotes.
|
||||
# Part of the regex is from http://stackoverflow.com/a/11503678
|
||||
echo "Checking for missing spaces after comments..."
|
||||
echo "${FILES}" | tr '\n' '\0' | xargs -0 perl -p -i -e 's/(?<!(:|\/))\/\/(?=[^ \/\n])(?=(?:[^"]*"[^"]*")*[^"]*\Z)/\/\/ /g'
|
||||
|
||||
git diff --exit-code -- ${FILES} || {
|
||||
echo "Some files were modified during code style checking."
|
||||
exit 1
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${WITH_COVERAGE} ] ; then
|
||||
echo "WITH_COVERAGE environment variable is not set, aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../"; pwd)
|
||||
|
||||
function usage() {
|
||||
echo "Error: LCOV and genhtml are required for generating coverage reports."
|
||||
if [ `uname -s` = 'Linux' ]; then
|
||||
echo "On Debian-based distros, you can install them via 'apt-get install lcov'"
|
||||
elif [ `uname -s` = 'Darwin' ]; then
|
||||
echo "On macOS, you can install them via 'brew install lcov'"
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v lcov >/dev/null 2>&1 || usage
|
||||
command -v genhtml >/dev/null 2>&1 || usage
|
||||
|
||||
# Build unit tests
|
||||
make test
|
||||
|
||||
# Zero coverage counters
|
||||
lcov \
|
||||
--quiet \
|
||||
--zerocounters \
|
||||
--directory "${SOURCE_DIR}" \
|
||||
--output-file "${SOURCE_DIR}/coverage.info" \
|
||||
>/dev/null 2>&1
|
||||
|
||||
# Run all unit tests
|
||||
make run-test
|
||||
|
||||
# Collect coverage data and save it into coverage.info
|
||||
echo "Collecting coverage data..."
|
||||
lcov \
|
||||
--quiet \
|
||||
--capture \
|
||||
--no-external \
|
||||
--directory "${SOURCE_DIR}" \
|
||||
--output-file "${SOURCE_DIR}/coverage.info" \
|
||||
>/dev/null 2>&1
|
||||
|
||||
# Remove coverage data for unwanted files from a tracefile
|
||||
lcov \
|
||||
--quiet \
|
||||
--remove "${SOURCE_DIR}/coverage.info" \
|
||||
"${SOURCE_DIR}/vendor/*" \
|
||||
"${SOURCE_DIR}/mason/*" \
|
||||
"${SOURCE_DIR}/test/*" \
|
||||
"/usr/include/*" \
|
||||
--output-file "${SOURCE_DIR}/total_coverage.info" \
|
||||
>/dev/null 2>&1
|
||||
|
||||
# Generate HTML report based on total_coverage.info
|
||||
echo "Generating HTML report..."
|
||||
genhtml \
|
||||
--quiet \
|
||||
--show-details \
|
||||
--keep-descriptions \
|
||||
--function-coverage \
|
||||
--no-branch-coverage \
|
||||
--title "Mapbox GL Native" \
|
||||
--num-spaces 4 \
|
||||
--sort \
|
||||
--demangle-cpp \
|
||||
--prefix $(pwd -P) \
|
||||
--output-directory "${SOURCE_DIR}/coverage" \
|
||||
"${SOURCE_DIR}/total_coverage.info" \
|
||||
>/dev/null 2>&1
|
||||
|
||||
echo "Coverage report is now available in ${SOURCE_DIR}/coverage/index.html"
|
||||
@@ -1,11 +0,0 @@
|
||||
// Do not edit -- generated by CMake
|
||||
|
||||
// mbgl-core
|
||||
mbgl_core_INCLUDE_DIRECTORIES = "$<JOIN:$<TARGET_PROPERTY:mbgl-core,INTERFACE_INCLUDE_DIRECTORIES>," ">"
|
||||
mbgl_core_LINK_LIBRARIES = "$<TARGET_PROPERTY:mbgl-core,XCODE_ATTRIBUTE_XCCONFIG_LINK_LIBRARIES>"
|
||||
|
||||
// mbgl-filesource
|
||||
mbgl_filesource_INCLUDE_DIRECTORIES = "$<JOIN:$<TARGET_PROPERTY:mbgl-filesource,INTERFACE_INCLUDE_DIRECTORIES>," ">"
|
||||
mbgl_filesource_LINK_LIBRARIES = "$<TARGET_PROPERTY:mbgl-filesource,XCODE_ATTRIBUTE_XCCONFIG_LINK_LIBRARIES>"
|
||||
|
||||
#include? "../../platform/darwin/developer.xcconfig"
|
||||
@@ -1,211 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- mode: python; coding: utf-8 -*-
|
||||
|
||||
# All files in doxy-coverage are Copyright 2014 Alvaro Lopez Ortega.
|
||||
#
|
||||
# Authors:
|
||||
# * Alvaro Lopez Ortega <alvaro@gnu.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
__author__ = "Alvaro Lopez Ortega"
|
||||
__email__ = "alvaro@alobbs.com"
|
||||
__copyright__ = "Copyright (C) 2014 Alvaro Lopez Ortega"
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
# Defaults
|
||||
ACCEPTABLE_COVERAGE = 80
|
||||
|
||||
# Global
|
||||
ns = None
|
||||
|
||||
def ERROR(*objs):
|
||||
print("ERROR: ", *objs, end='\n', file=sys.stderr)
|
||||
|
||||
def FATAL(*objs):
|
||||
ERROR (*objs)
|
||||
sys.exit((1,0)[ns.noerror])
|
||||
|
||||
def parse_file(fullpath):
|
||||
tree = ET.parse(fullpath)
|
||||
|
||||
sourcefile = None
|
||||
definitions = {}
|
||||
|
||||
for definition in tree.findall("./compounddef//memberdef"):
|
||||
# Should it be documented
|
||||
if definition.get('prot') == 'private' or (
|
||||
definition.get('kind') == 'function' and
|
||||
definition.get('static') == 'yes'):
|
||||
continue
|
||||
|
||||
# Is the definition documented?
|
||||
documented = False
|
||||
for k in ('briefdescription', 'detaileddescription', 'inbodydescription'):
|
||||
if definition.findall("./%s/"%(k)):
|
||||
documented = True
|
||||
break
|
||||
|
||||
# Name
|
||||
d_def = definition.find('./definition')
|
||||
d_nam = definition.find('./name')
|
||||
|
||||
if not sourcefile:
|
||||
l = definition.find('./location')
|
||||
if l is not None:
|
||||
sourcefile = l.get('file')
|
||||
|
||||
if d_def is not None:
|
||||
name = d_def.text
|
||||
elif d_nam is not None:
|
||||
name = d_nam.text
|
||||
else:
|
||||
name = definition.get('id')
|
||||
|
||||
# Aggregate
|
||||
definitions[name] = documented
|
||||
|
||||
if not sourcefile:
|
||||
sourcefile = fullpath
|
||||
|
||||
return (sourcefile, definitions)
|
||||
|
||||
|
||||
def parse(path):
|
||||
index_fp = os.path.join (path, "index.xml")
|
||||
if not os.path.exists (index_fp):
|
||||
FATAL ("Documentation not present. Exiting.", index_fp)
|
||||
|
||||
tree = ET.parse(index_fp)
|
||||
|
||||
files = {}
|
||||
for entry in tree.findall('compound'):
|
||||
if entry.get('kind') in ('dir'):
|
||||
continue
|
||||
|
||||
file_fp = os.path.join (path, "%s.xml" %(entry.get('refid')))
|
||||
tmp = parse_file (file_fp)
|
||||
files[tmp[0]] = tmp[1]
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def report (files, exclude_dirs):
|
||||
def get_coverage (f):
|
||||
defs = files[f]
|
||||
if not defs:
|
||||
return 100
|
||||
|
||||
doc_yes = len([d for d in defs.values() if d])
|
||||
doc_no = len([d for d in defs.values() if not d])
|
||||
return (doc_yes * 100.0 / (doc_yes + doc_no))
|
||||
|
||||
def file_cmp (a,b):
|
||||
return cmp(get_coverage(a), get_coverage(b))
|
||||
|
||||
files_sorted = files.keys()
|
||||
files_sorted.sort(file_cmp)
|
||||
files_sorted.reverse()
|
||||
|
||||
total_yes = 0
|
||||
total_no = 0
|
||||
|
||||
for f in files_sorted:
|
||||
skip = False
|
||||
for exclude_dir in exclude_dirs:
|
||||
if exclude_dir in f:
|
||||
skip = True
|
||||
break
|
||||
if skip:
|
||||
continue
|
||||
|
||||
defs = files[f]
|
||||
if not defs:
|
||||
continue
|
||||
|
||||
doc_yes = len([d for d in defs.values() if d])
|
||||
doc_no = len([d for d in defs.values() if not d])
|
||||
doc_per = doc_yes * 100.0 / (doc_yes + doc_no)
|
||||
|
||||
total_yes += doc_yes
|
||||
total_no += doc_no
|
||||
|
||||
if not ns.quiet:
|
||||
print ('%3d%% - %s - (%d of %d)'%(doc_per, f, doc_yes, (doc_yes + doc_no)))
|
||||
|
||||
defs_sorted = defs.keys()
|
||||
defs_sorted.sort()
|
||||
for d in defs_sorted:
|
||||
if not defs[d]:
|
||||
print ("\t", d)
|
||||
|
||||
total_all = total_yes + total_no
|
||||
total_per = total_yes * 100 / total_all
|
||||
if not ns.quiet:
|
||||
print()
|
||||
print("%d%% API documentation coverage (%d out of %d)" %(total_per, total_yes, total_all))
|
||||
|
||||
if ns.json:
|
||||
with open(ns.json, "w") as f:
|
||||
f.write('{"documented": %d, "total": %d}\n' % (total_yes, total_all))
|
||||
|
||||
return (ns.threshold - total_per, 0)[total_per > ns.threshold]
|
||||
|
||||
|
||||
def main():
|
||||
# Arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument ("dir", action="store", help="Path to Doxygen's XML doc directory")
|
||||
parser.add_argument ("--noerror", action="store_true", help="Do not return error code after execution")
|
||||
parser.add_argument ("--threshold", action="store", help="Min acceptable coverage percentage (Default: %s)"%(ACCEPTABLE_COVERAGE), default=ACCEPTABLE_COVERAGE, type=int)
|
||||
parser.add_argument ("--quiet", action="store_true", help="Don't output report to standard output")
|
||||
parser.add_argument ("--json", action="store", help="Output json coverage report to specified json file")
|
||||
parser.add_argument("--excludedirs", nargs='+', help="List of directories to be excluded from coverage analysis", type=str, default=[])
|
||||
|
||||
|
||||
global ns
|
||||
ns = parser.parse_args()
|
||||
if not ns:
|
||||
FATAL ("ERROR: Couldn't parse parameters")
|
||||
|
||||
# Parse
|
||||
files = parse (ns.dir)
|
||||
|
||||
# Print report
|
||||
err = report (files, ns.excludedirs)
|
||||
if ns.noerror:
|
||||
return
|
||||
|
||||
sys.exit(err)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Output some `export` commands with a few extra environment variables. They'll be evaluated
|
||||
// into the build environment and available for use in later steps.
|
||||
|
||||
const github = require('@octokit/rest')();
|
||||
const {execSync} = require('child_process');
|
||||
|
||||
const pr = process.env['GITHUB_PULL_REQUEST'];
|
||||
if (pr) {
|
||||
const number = +pr.match(/\/(\d+)\/?$/)[1];
|
||||
return github.pullRequests.get({
|
||||
owner: 'maplibre',
|
||||
repo: 'maplibre-gl-native',
|
||||
number
|
||||
}).then(({data}) => {
|
||||
const base = data.base.ref;
|
||||
const head = process.env['GITHUB_SHA'];
|
||||
const mergeBase = execSync(`git merge-base origin/${base} ${head}`).toString().trim();
|
||||
|
||||
console.log(`export GITHUB_TARGET_BRANCH=${base}`);
|
||||
console.log(`export GITHUB_MERGE_BASE=${mergeBase}`);
|
||||
});
|
||||
} else {
|
||||
const head = process.env['GITHUB_SHA'];
|
||||
for (const sha of execSync(`git rev-list --max-count=500 ${head}`).toString().trim().split('\n')) {
|
||||
const base = execSync(`git branch -r --contains ${sha} origin/main origin/release-*`).toString().split('\n')[0].trim().replace(/^origin\//, '');
|
||||
if (base) {
|
||||
const mergeBase = execSync(`git merge-base origin/${base} ${head}`).toString().trim();
|
||||
console.log(`export GITHUB_TARGET_BRANCH=${base}`);
|
||||
console.log(`export GITHUB_MERGE_BASE=${mergeBase}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('@mapbox/flow-remove-types/register');
|
||||
|
||||
const path = require('path');
|
||||
const outputPath = 'src/mbgl/programs';
|
||||
const zlib = require('zlib');
|
||||
const crypto = require('crypto');
|
||||
|
||||
var shaders = require('../maplibre-gl-js/src/shaders');
|
||||
|
||||
require('../../../scripts/style-code');
|
||||
|
||||
let concatenated = '';
|
||||
let offsets = {};
|
||||
|
||||
function basicMinify(src) {
|
||||
return src = src.trim() // strip whitespace at the start/end
|
||||
.replace(/\s*\/\/[^\n]*\n/g, '\n') // strip double-slash comments
|
||||
.replace(/\n+/g, '\n') // collapse multi line breaks
|
||||
.replace(/\n\s+/g, '\n') // strip identation
|
||||
.replace(/\s?([+-\/*=,])\s?/g, '$1') // strip whitespace around operators
|
||||
.replace(/([;\(\),\{\}])\n(?=[^#])/g, '$1'); // strip more line breaks
|
||||
}
|
||||
|
||||
for (const key in shaders) {
|
||||
// Rename a_*_t uniforms to u_*_t. This is a workaround until we can use
|
||||
// https://github.com/mapbox/mapbox-gl-js/pull/8055, which is blocked by
|
||||
// https://github.com/mapbox/mapbox-gl-native/issues/13984
|
||||
shaders[key].vertexSource = shaders[key].vertexSource.replace(/\ba_(\w+)_t\b/mg, 'u_$1_t');
|
||||
|
||||
const hash = crypto.createHash('sha1');
|
||||
|
||||
const vertex = concatenated.length;
|
||||
const vertexSource = basicMinify(shaders[key].vertexSource) + '\n\0';
|
||||
hash.update(vertexSource);
|
||||
concatenated += vertexSource;
|
||||
|
||||
const fragment = concatenated.length;
|
||||
const fragmentSource = basicMinify(shaders[key].fragmentSource) + '\n\0';
|
||||
hash.update(fragmentSource);
|
||||
concatenated += fragmentSource;
|
||||
|
||||
offsets[key] = {
|
||||
vertex,
|
||||
fragment,
|
||||
originalKey: key,
|
||||
hash: hash.digest('hex').substring(0, 16).match(/.{1,2}/g).map(n => `0x${n}`).join(', '),
|
||||
shaderName: key.replace(/[A-Z]+/g, (match) => `_${match.toLowerCase()}`),
|
||||
ShaderName: key.replace(/^[a-z]/g, (match) => match.toUpperCase())
|
||||
};
|
||||
}
|
||||
|
||||
// Overrides: The symbolSDF shader is used for two underlying programs.
|
||||
offsets.symbolSDFIcon = {
|
||||
vertex: offsets.symbolSDF.vertex,
|
||||
fragment: offsets.symbolSDF.fragment,
|
||||
hash: offsets.symbolSDF.hash,
|
||||
originalKey: 'symbolSDF',
|
||||
shaderName: 'symbol_sdf_icon',
|
||||
ShaderName: 'SymbolSDFIcon',
|
||||
};
|
||||
|
||||
offsets.symbolSDFText = {
|
||||
vertex: offsets.symbolSDF.vertex,
|
||||
fragment: offsets.symbolSDF.fragment,
|
||||
hash: offsets.symbolSDF.hash,
|
||||
originalKey: 'symbolSDF',
|
||||
shaderName: 'symbol_sdf_text',
|
||||
ShaderName: 'SymbolSDFText',
|
||||
};
|
||||
|
||||
delete offsets.symbolSDF;
|
||||
|
||||
const compressed = zlib.deflateSync(concatenated, {level: zlib.Z_BEST_COMPRESSION})
|
||||
.toString('hex')
|
||||
.match(/.{1,32}/g)
|
||||
.map(line => line.match(/.{1,2}/g).map(n => `0x${n}`).join(', '))
|
||||
.join(',\n ')
|
||||
.trim();
|
||||
|
||||
writeIfModified(path.join(outputPath, 'gl', 'shader_source.hpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace mbgl {
|
||||
namespace programs {
|
||||
namespace gl {
|
||||
|
||||
const char* shaderSource();
|
||||
|
||||
template <typename>
|
||||
struct ShaderSource;
|
||||
|
||||
} // namespace gl
|
||||
} // namespace programs
|
||||
} // namespace mbgl
|
||||
`);
|
||||
|
||||
writeIfModified(path.join(outputPath, 'gl', 'shader_source.cpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
|
||||
|
||||
#include <mbgl/programs/gl/shader_source.hpp>
|
||||
#include <mbgl/util/compression.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mbgl {
|
||||
namespace programs {
|
||||
namespace gl {
|
||||
|
||||
constexpr const uint8_t compressedShaderSource[] = {
|
||||
${compressed}
|
||||
};
|
||||
|
||||
const char* shaderSource() {
|
||||
static std::string decompressed = util::decompress(std::string(reinterpret_cast<const char*>(compressedShaderSource), sizeof(compressedShaderSource)));
|
||||
return decompressed.c_str();
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace programs
|
||||
} // namespace mbgl
|
||||
`);
|
||||
|
||||
writeIfModified(path.join(outputPath, 'gl', 'preludes.hpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mbgl {
|
||||
namespace programs {
|
||||
namespace gl {
|
||||
|
||||
constexpr const uint8_t preludeHash[8] = { ${offsets['prelude'].hash} };
|
||||
constexpr const auto vertexPreludeOffset = ${offsets['prelude'].vertex};
|
||||
constexpr const auto fragmentPreludeOffset = ${offsets['prelude'].fragment};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace programs
|
||||
} // namespace mbgl
|
||||
`);
|
||||
|
||||
for (const key in offsets) {
|
||||
if (key === 'prelude')
|
||||
continue;
|
||||
|
||||
const { shaderName, ShaderName, originalKey } = offsets[key];
|
||||
|
||||
writeIfModified(path.join(outputPath, 'gl', `${shaderName}.cpp`), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
|
||||
|
||||
#include <mbgl/programs/${shaderName}_program.hpp>
|
||||
#include <mbgl/programs/gl/preludes.hpp>
|
||||
#include <mbgl/programs/gl/shader_source.hpp>
|
||||
#include <mbgl/gl/program.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace programs {
|
||||
namespace gl {
|
||||
|
||||
template <typename>
|
||||
struct ShaderSource;
|
||||
|
||||
template <>
|
||||
struct ShaderSource<${ShaderName}Program> {
|
||||
static constexpr const char* name = "${shaderName}";
|
||||
static constexpr const uint8_t hash[8] = { ${offsets[key].hash} };
|
||||
static constexpr const auto vertexOffset = ${offsets[key].vertex};
|
||||
static constexpr const auto fragmentOffset = ${offsets[key].fragment};
|
||||
};
|
||||
|
||||
constexpr const char* ShaderSource<${ShaderName}Program>::name;
|
||||
constexpr const uint8_t ShaderSource<${ShaderName}Program>::hash[8];
|
||||
|
||||
} // namespace gl
|
||||
} // namespace programs
|
||||
|
||||
namespace gfx {
|
||||
|
||||
template <>
|
||||
std::unique_ptr<gfx::Program<${ShaderName}Program>>
|
||||
Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) {
|
||||
return std::make_unique<gl::Program<${ShaderName}Program>>(programParameters);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mbgl
|
||||
|
||||
// Uncompressed source of ${shaderName}.vertex.glsl:
|
||||
/*
|
||||
${shaders[originalKey].vertexSource}
|
||||
*/
|
||||
|
||||
// Uncompressed source of ${shaderName}.fragment.glsl:
|
||||
/*
|
||||
${shaders[originalKey].fragmentSource}
|
||||
*/
|
||||
|
||||
`);
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const ejs = require('ejs');
|
||||
const spec = require('./style-spec');
|
||||
const colorParser = require('csscolorparser');
|
||||
|
||||
require('../../../scripts/style-code');
|
||||
|
||||
function parseCSSColor(str) {
|
||||
const color = colorParser.parseCSSColor(str);
|
||||
return [
|
||||
color[0] / 255 * color[3], color[1] / 255 * color[3], color[2] / 255 * color[3], color[3]
|
||||
];
|
||||
}
|
||||
|
||||
global.isLightProperty = function (property) {
|
||||
return property['light-property'] === true;
|
||||
};
|
||||
|
||||
global.isOverridable = function (property) {
|
||||
return ['text-color'].includes(property.name);
|
||||
};
|
||||
|
||||
global.expressionType = function (property) {
|
||||
switch (property.type) {
|
||||
case 'boolean':
|
||||
return 'BooleanType';
|
||||
case 'number':
|
||||
case 'enum':
|
||||
return 'NumberType';
|
||||
case 'string':
|
||||
case 'image': // TODO: replace once we implement image expressions
|
||||
return 'StringType';
|
||||
case 'color':
|
||||
return `ColorType`;
|
||||
case 'formatted':
|
||||
return `FormattedType`;
|
||||
case 'array':
|
||||
return `Array<${expressionType({type: property.value})}>`;
|
||||
default: throw new Error(`unknown type for ${property.name}`)
|
||||
}
|
||||
};
|
||||
|
||||
global.evaluatedType = function (property) {
|
||||
if (/-translate-anchor$/.test(property.name)) {
|
||||
return 'TranslateAnchorType';
|
||||
}
|
||||
if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) {
|
||||
return 'AlignmentType';
|
||||
}
|
||||
if (/^(text|icon)-anchor$/.test(property.name)) {
|
||||
return 'SymbolAnchorType';
|
||||
}
|
||||
if (/position/.test(property.name)) {
|
||||
return 'Position';
|
||||
}
|
||||
switch (property.type) {
|
||||
case 'boolean':
|
||||
return 'bool';
|
||||
case 'number':
|
||||
return 'float';
|
||||
case 'formatted':
|
||||
return 'expression::Formatted';
|
||||
case 'string':
|
||||
case 'image': // TODO: replace once we implement image expressions
|
||||
return 'std::string';
|
||||
case 'enum':
|
||||
return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`;
|
||||
case 'color':
|
||||
return `Color`;
|
||||
case 'array':
|
||||
if (property.length) {
|
||||
return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`;
|
||||
} else {
|
||||
return `std::vector<${evaluatedType({type: property.value, name: property.name})}>`;
|
||||
}
|
||||
default: throw new Error(`unknown type for ${property.name}`)
|
||||
}
|
||||
};
|
||||
|
||||
function attributeUniformType(property, type) {
|
||||
const attributeNameExceptions = {
|
||||
'text-opacity': ['opacity'],
|
||||
'icon-opacity': ['opacity'],
|
||||
'text-color': ['fill_color'],
|
||||
'icon-color': ['fill_color'],
|
||||
'text-halo-color': ['halo_color'],
|
||||
'icon-halo-color': ['halo_color'],
|
||||
'text-halo-blur': ['halo_blur'],
|
||||
'icon-halo-blur': ['halo_blur'],
|
||||
'text-halo-width': ['halo_width'],
|
||||
'icon-halo-width': ['halo_width'],
|
||||
'line-gap-width': ['gapwidth'],
|
||||
'line-pattern': ['pattern_to', 'pattern_from'],
|
||||
'line-floor-width': ['floorwidth'],
|
||||
'fill-pattern': ['pattern_to', 'pattern_from'],
|
||||
'fill-extrusion-pattern': ['pattern_to', 'pattern_from']
|
||||
}
|
||||
const names = attributeNameExceptions[property.name] ||
|
||||
[ property.name.replace(type + '-', '').replace(/-/g, '_') ];
|
||||
|
||||
return names.map(name => {
|
||||
return `attributes::${name}, uniforms::${name}`
|
||||
}).join(', ');
|
||||
}
|
||||
|
||||
global.layoutPropertyType = function (property) {
|
||||
switch (property['property-type']) {
|
||||
case 'data-driven':
|
||||
case 'cross-faded-data-driven':
|
||||
return `DataDrivenLayoutProperty<${evaluatedType(property)}>`;
|
||||
default:
|
||||
return `LayoutProperty<${evaluatedType(property)}>`;
|
||||
}
|
||||
};
|
||||
|
||||
global.paintPropertyType = function (property, type) {
|
||||
switch (property['property-type']) {
|
||||
case 'data-driven':
|
||||
if (isOverridable(property))
|
||||
return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}, true>`;
|
||||
return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
|
||||
case 'cross-faded-data-driven':
|
||||
return `CrossFadedDataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
|
||||
case 'cross-faded':
|
||||
return `CrossFadedPaintProperty<${evaluatedType(property)}>`;
|
||||
default:
|
||||
return `PaintProperty<${evaluatedType(property)}>`;
|
||||
}
|
||||
};
|
||||
|
||||
global.propertyValueType = function (property) {
|
||||
switch (property['property-type']) {
|
||||
case 'color-ramp':
|
||||
return `ColorRampPropertyValue`;
|
||||
default:
|
||||
return `PropertyValue<${evaluatedType(property)}>`;
|
||||
}
|
||||
};
|
||||
|
||||
global.defaultValue = function (property) {
|
||||
// https://github.com/mapbox/mapbox-gl-native/issues/5258
|
||||
if (property.name === 'line-round-limit') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (property.name === 'fill-outline-color') {
|
||||
return '{}';
|
||||
}
|
||||
|
||||
if (property['property-type'] === 'color-ramp') {
|
||||
return '{}';
|
||||
}
|
||||
|
||||
switch (property.type) {
|
||||
case 'number':
|
||||
if (property.default === undefined) {
|
||||
return 0;
|
||||
} else {
|
||||
return property.default;
|
||||
}
|
||||
case 'formatted':
|
||||
case 'string':
|
||||
case 'image': // TODO: replace once we implement image expressions
|
||||
return JSON.stringify(property.default || "");
|
||||
case 'enum':
|
||||
if (property.default === undefined) {
|
||||
return `${evaluatedType(property)}::Undefined`;
|
||||
} else {
|
||||
return `${evaluatedType(property)}::${camelize(property.default)}`;
|
||||
}
|
||||
case 'color':
|
||||
const color = parseCSSColor(property.default).join(', ');
|
||||
switch (color) {
|
||||
case '0, 0, 0, 0':
|
||||
return '{}';
|
||||
case '0, 0, 0, 1':
|
||||
return 'Color::black()';
|
||||
case '1, 1, 1, 1':
|
||||
return 'Color::white()';
|
||||
default:
|
||||
return `{ ${color} }`;
|
||||
}
|
||||
case 'array':
|
||||
const defaults = (property.default || []).map((e) => defaultValue({ type: property.value, default: e }));
|
||||
if (property.length) {
|
||||
return `{{ ${defaults.join(', ')} }}`;
|
||||
} else {
|
||||
return `{ ${defaults.join(', ')} }`;
|
||||
}
|
||||
default:
|
||||
return property.default;
|
||||
}
|
||||
};
|
||||
|
||||
const layerHpp = ejs.compile(fs.readFileSync('include/mbgl/style/layers/layer.hpp.ejs', 'utf8'), {strict: true});
|
||||
const layerCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer.cpp.ejs', 'utf8'), {strict: true});
|
||||
const propertiesHpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.hpp.ejs', 'utf8'), {strict: true});
|
||||
const propertiesCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.cpp.ejs', 'utf8'), {strict: true});
|
||||
|
||||
const collator = new Intl.Collator("en-US");
|
||||
|
||||
// Add this mock property that our SDF line shader needs so that it gets added to the list of
|
||||
// "data driven" properties.
|
||||
spec.paint_line['line-floor-width'] = {
|
||||
"type": "number",
|
||||
"default": 1,
|
||||
"property-type": "data-driven"
|
||||
};
|
||||
|
||||
const layers = Object.keys(spec.layer.type.values).map((type) => {
|
||||
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
|
||||
if (name !== 'visibility') {
|
||||
spec[`layout_${type}`][name].name = name;
|
||||
memo.push(spec[`layout_${type}`][name]);
|
||||
}
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
// JSON doesn't have a defined order. We're going to sort them alphabetically
|
||||
// to get a deterministic order.
|
||||
layoutProperties.sort((a, b) => collator.compare(a.name, b.name));
|
||||
|
||||
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
|
||||
spec[`paint_${type}`][name].name = name;
|
||||
memo.push(spec[`paint_${type}`][name]);
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
// JSON doesn't have a defined order. We're going to sort them alphabetically
|
||||
// to get a deterministic order.
|
||||
paintProperties.sort((a, b) => collator.compare(a.name, b.name));
|
||||
|
||||
return {
|
||||
type: type,
|
||||
layoutProperties: layoutProperties,
|
||||
paintProperties: paintProperties,
|
||||
doc: spec.layer.type.values[type].doc,
|
||||
layoutPropertiesByName: spec[`layout_${type}`],
|
||||
paintPropertiesByName: spec[`paint_${type}`],
|
||||
};
|
||||
});
|
||||
|
||||
for (const layer of layers) {
|
||||
const layerFileName = layer.type.replace('-', '_');
|
||||
|
||||
writeIfModified(`src/mbgl/style/layers/${layerFileName}_layer_properties.hpp`, propertiesHpp(layer));
|
||||
writeIfModified(`src/mbgl/style/layers/${layerFileName}_layer_properties.cpp`, propertiesCpp(layer));
|
||||
|
||||
// Remove our fake property for the external interace.
|
||||
if (layer.type === 'line') {
|
||||
layer.paintProperties = layer.paintProperties.filter(property => property.name !== 'line-floor-width');
|
||||
}
|
||||
|
||||
writeIfModified(`include/mbgl/style/layers/${layerFileName}_layer.hpp`, layerHpp(layer));
|
||||
writeIfModified(`src/mbgl/style/layers/${layerFileName}_layer.cpp`, layerCpp(layer));
|
||||
}
|
||||
|
||||
// Light
|
||||
const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => {
|
||||
var property = spec[`light`][name];
|
||||
property.name = name;
|
||||
property['light-property'] = true;
|
||||
memo.push(property);
|
||||
return memo;
|
||||
}, []);
|
||||
|
||||
// JSON doesn't have a defined order. We're going to sort them alphabetically
|
||||
// to get a deterministic order.
|
||||
lightProperties.sort((a, b) => collator.compare(a.name, b.name));
|
||||
|
||||
const lightHpp = ejs.compile(fs.readFileSync('include/mbgl/style/light.hpp.ejs', 'utf8'), {strict: true});
|
||||
const lightCpp = ejs.compile(fs.readFileSync('src/mbgl/style/light.cpp.ejs', 'utf8'), {strict: true});
|
||||
writeIfModified(`include/mbgl/style/light.hpp`, lightHpp({properties: lightProperties}));
|
||||
writeIfModified(`src/mbgl/style/light.cpp`, lightCpp({properties: lightProperties}));
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CCACHE_CPP2=true
|
||||
exec "@C_LAUNCHER@" "${PATH%%/Contents/Developer/*}/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" "$@"
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CCACHE_CPP2=true
|
||||
exec "@C_LAUNCHER@" "$@"
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CCACHE_CPP2=true
|
||||
exec "@CXX_LAUNCHER@" "${PATH%%/Contents/Developer/*}/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++" "$@"
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export CCACHE_CPP2=true
|
||||
exec "@CXX_LAUNCHER@" "$@"
|
||||
@@ -1,15 +0,0 @@
|
||||
type summary add "mbgl::CanonicalTileID" --summary-string "${var.z%u}/${var.x}/${var.y}"
|
||||
type summary add "mbgl::UnwrappedTileID" --summary-string "${var.canonical}+${var.wrap}"
|
||||
type summary add "mbgl::OverscaledTileID" --summary-string "${var.canonical}=>${var.overscaledZ%u}"
|
||||
|
||||
type summary add -e -x "^mbgl::Range<.+>$" --summary-string "${var.min%d} ⇒ ${var.max%d}"
|
||||
type summary add -e -x "^mbgl::Rect<.+>$" --summary-string "Size: ${var.w%d}×${var.h%d} — Offset: ${var.x}/${var.y}"
|
||||
type summary add "mbgl::Size" --summary-string "${var.width}/${var.height}"
|
||||
type summary add "mbgl::LatLng" --summary-string "${var.lat}/${var.lon}"
|
||||
|
||||
type summary add "mbgl::Color" --summary-string "${var.r}, ${var.g}, ${var.b}, ${var.a}"
|
||||
|
||||
type summary add -e -x "^mbgl::Point<.+>$" --summary-string "${var.x}/${var.y}"
|
||||
type summary add -e -x "^mapbox::geometry::point<.+>$" --summary-string "${var.x}/${var.y}"
|
||||
|
||||
type summary add -e -x "^mbgl::optional<.+>$" --python-script "return valobj.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(1).GetValue() if valobj.GetChildMemberWithName('__engaged_').unsigned > 0 else '<empty>'"
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
set -u
|
||||
|
||||
# Logs metrics on memory usage to CloudWatch
|
||||
|
||||
GTEST_OUTPUT=$1
|
||||
DIMENSIONS=$2
|
||||
|
||||
if [ -z "${DIMENSIONS}" ]; then
|
||||
echo "* No dimensions specified for memory benchmarks"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function reportAttributeValue {
|
||||
ATTR_NAME=$1
|
||||
ATTR_UNITS=$2
|
||||
ATTR_VALUE=$(cat $GTEST_OUTPUT | grep -o "$ATTR_NAME=\"[^\"]*" | sed "s/$ATTR_NAME=\"//")
|
||||
if [ ${CLOUDWATCH:-} ]; then
|
||||
echo "* Reporting $ATTR_NAME = $ATTR_VALUE $ATTR_UNITS for '${DIMENSIONS}'"
|
||||
aws --region us-east-1 cloudwatch put-metric-data \
|
||||
--namespace "Mapbox/GL" \
|
||||
--metric-name "$ATTR_NAME" \
|
||||
--unit "$ATTR_UNITS" \
|
||||
--value ${ATTR_VALUE} \
|
||||
--dimensions "${DIMENSIONS}"
|
||||
else
|
||||
echo "* Measured $ATTR_NAME = $ATTR_VALUE $ATTR_UNITS for '${DIMENSIONS}'"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -f "${GTEST_OUTPUT}" ]; then
|
||||
reportAttributeValue vectorFootprint Bytes
|
||||
reportAttributeValue rasterFootprint Bytes
|
||||
else
|
||||
echo "* File '${GTEST_OUTPUT}' does not exist"
|
||||
fi
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cmake -P cmake/mason.cmake "$@"
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
const nitpick = require('.');
|
||||
const child_process = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
|
||||
function checkGeneratedFiles(name, scripts) {
|
||||
var files = [];
|
||||
|
||||
scripts.forEach(function(script) {
|
||||
child_process.execSync(script);
|
||||
const list = path.join(path.dirname(script), path.basename(script, path.extname(script)) + '.list');
|
||||
files.push(list);
|
||||
files = files.concat(fs.readFileSync(list, 'utf8').split('\n'));
|
||||
});
|
||||
|
||||
// List missing files
|
||||
var missing = child_process.execFileSync('git', ['ls-files', '--others', '--exclude-standard', '--'].concat(files)).toString().trim();
|
||||
if (!missing.length) {
|
||||
nitpick.ok(`All generated ${name} files are checked in`);
|
||||
} else {
|
||||
nitpick.fail(`These generated ${name} files are not checked in:`, missing);
|
||||
}
|
||||
|
||||
// Diff existing files
|
||||
var diff = child_process.execFileSync('git', ['-c', 'color.ui=always', 'diff', 'HEAD', '--'].concat(files)).toString().trim();
|
||||
if (!diff.length) {
|
||||
nitpick.ok(`All generated ${name} files are up-to-date`);
|
||||
} else {
|
||||
nitpick.fail(`These generated ${name} files have modifications:`, diff);
|
||||
}
|
||||
}
|
||||
|
||||
const mode = (process.argv[2] || '').toLowerCase();
|
||||
if (!mode || mode == 'sources') {
|
||||
checkGeneratedFiles('Source list', ['scripts/generate-file-lists.js']);
|
||||
}
|
||||
if (!mode || mode == 'shader') {
|
||||
checkGeneratedFiles('shader', ['scripts/generate-shaders.js']);
|
||||
}
|
||||
if (!mode || mode == 'style') {
|
||||
checkGeneratedFiles('style', ['scripts/generate-style-code.js']);
|
||||
}
|
||||
if (!mode || mode == 'android') {
|
||||
checkGeneratedFiles('Android', ['platform/android/scripts/generate-style-code.js']);
|
||||
}
|
||||
if ((!mode || mode == 'darwin') && os.platform() == 'darwin') {
|
||||
checkGeneratedFiles('Darwin', ['platform/darwin/scripts/generate-style-code.js', 'platform/darwin/scripts/update-examples.js']);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
var failed = false;
|
||||
|
||||
process.on('exit', function() {
|
||||
if (failed) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = function(status, str, desc) {
|
||||
if (status) {
|
||||
console.warn(`\x1b[1m\x1b[32m✔︎ ${str}\x1b[0m`);
|
||||
} else {
|
||||
console.warn(`\x1b[1m\x1b[31m✘ ${str}\x1b[0m`);
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (desc) {
|
||||
console.warn(`${desc.split('\n').map((line) => '| ' + line).join('\n')}\n`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.ok = function(str, desc) {
|
||||
module.exports(true, str, desc);
|
||||
};
|
||||
|
||||
module.exports.fail = function(str, desc) {
|
||||
module.exports(false, str, desc);
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
const nitpick = require('.');
|
||||
const child_process = require('child_process');
|
||||
|
||||
// Make sure that the maplibre-gl-js submodule pin is up to date
|
||||
const head = child_process.execSync('git -C maplibre-gl-js rev-parse HEAD').toString().trim();
|
||||
const revs = child_process.execSync(`git -C maplibre-gl-js branch -a --contains ${head}`).toString().split('\n');
|
||||
|
||||
if (revs.indexOf(' remotes/origin/main') >= 0) {
|
||||
nitpick.ok(`maplibre-gl-js submodule pin is merged to main`);
|
||||
} else {
|
||||
nitpick.fail(`maplibre-gl-js submodule is pinned to ${head}, which isn't merged to main`);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
set -u
|
||||
|
||||
SLACK_CHANNEL=${SLACK_CHANNEL:-''}
|
||||
SLACK_COLOR=${SLACK_COLOR:-''}
|
||||
|
||||
curl -g -H "Content-Type: application/json" -X POST \
|
||||
-d "{\"channel\": \"$SLACK_CHANNEL\", \"attachments\": [{\"text\": \"$SLACK_MESSAGE\", \"color\": \"$SLACK_COLOR\", \"author_name\": \"$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME\"}]}" \
|
||||
$SLACK_WEBHOOK_URL
|
||||
@@ -1,178 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const github = require('@octokit/rest').plugin(require('@octokit/plugin-retry'))({
|
||||
retry: { doNotRetry: [ /* Empty — retry on any error code. */ ] }
|
||||
})
|
||||
const zlib = require('zlib');
|
||||
const AWS = require('aws-sdk');
|
||||
|
||||
const SIZE_CHECK_APP_ID = 14028;
|
||||
const SIZE_CHECK_APP_INSTALLATION_ID = 229425;
|
||||
|
||||
process.on('unhandledRejection', error => {
|
||||
console.log(error);
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY'];
|
||||
if (!pk) {
|
||||
console.log('Fork PR; not publishing size.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const key = Buffer.from(pk, 'base64').toString('binary');
|
||||
const payload = {
|
||||
exp: Math.floor(Date.now() / 1000) + 60,
|
||||
iat: Math.floor(Date.now() / 1000),
|
||||
iss: SIZE_CHECK_APP_ID
|
||||
};
|
||||
|
||||
const token = jwt.sign(payload, key, {algorithm: 'RS256'});
|
||||
github.authenticate({type: 'app', token});
|
||||
|
||||
// Must be in sync with the definition in metrics/binary-size/index.html on the gh-pages branch.
|
||||
const platforms = [
|
||||
{ 'platform': 'iOS', 'arch': 'armv7' },
|
||||
{ 'platform': 'iOS', 'arch': 'arm64' },
|
||||
{ 'platform': 'iOS', 'arch': 'Dynamic' },
|
||||
{ 'platform': 'Android', 'arch': 'arm-v7' },
|
||||
{ 'platform': 'Android', 'arch': 'arm-v8' },
|
||||
{ 'platform': 'Android', 'arch': 'x86' },
|
||||
{ 'platform': 'Android', 'arch': 'x86_64' }
|
||||
];
|
||||
|
||||
const sizeCheckInfo = [];
|
||||
const rows = [];
|
||||
const date = new Date().toISOString().substring(0, 19);
|
||||
|
||||
function query(after) {
|
||||
return github.request({
|
||||
method: 'POST',
|
||||
url: '/graphql',
|
||||
headers: {
|
||||
// https://developer.github.com/changes/2018-07-11-graphql-checks-preview/
|
||||
accept: 'application/vnd.github.antiope-preview'
|
||||
},
|
||||
query: `query {
|
||||
repository(owner: "mapbox", name: "mapbox-gl-native") {
|
||||
ref(qualifiedName: "main") {
|
||||
target {
|
||||
... on Commit {
|
||||
history(first: 100, before: "36c6a8ea79bbd2596abb58ffb58debf65a4ea13d" ${after ? `, after: "${after}"` : ''}) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
oid
|
||||
messageHeadline
|
||||
checkSuites(first: 1, filterBy: {appId: ${SIZE_CHECK_APP_ID}}) {
|
||||
nodes {
|
||||
checkRuns(first: 10) {
|
||||
nodes {
|
||||
name
|
||||
conclusion
|
||||
title
|
||||
summary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
}).then((result) => {
|
||||
|
||||
const history = result.data.data.repository.ref.target.history;
|
||||
|
||||
for (const edge of history.edges) {
|
||||
const commit = edge.node;
|
||||
const suite = commit.checkSuites.nodes[0];
|
||||
|
||||
if (!suite)
|
||||
continue;
|
||||
const allRuns = commit.checkSuites.nodes[0].checkRuns.nodes;
|
||||
|
||||
const sizeCheckRuns = allRuns.filter(function (run) {
|
||||
return run.name.match(/Size - (\w+) ([\w-]+)/);
|
||||
});
|
||||
|
||||
const row = [`${commit.oid.slice(0, 7)} - ${commit.messageHeadline}`];
|
||||
|
||||
for (let i = 0; i < platforms.length; i++) {
|
||||
const {platform, arch} = platforms[i];
|
||||
|
||||
const run = sizeCheckRuns.find((run) => {
|
||||
const [, p, a] = run.name.match(/Size - (\w+) ([\w-]+)/);
|
||||
return platform === p && arch === a;
|
||||
});
|
||||
|
||||
row[i + 1] = run ? +run.summary.match(/is (\d+) bytes/)[1] : undefined;
|
||||
}
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
if (history.pageInfo.hasNextPage) {
|
||||
return query(history.pageInfo.endCursor);
|
||||
} else {
|
||||
const latestRun = rows[0]
|
||||
const runSizeMeasurements = latestRun.slice(1)
|
||||
|
||||
for (let i = 0; i < platforms.length; i++) {
|
||||
const {platform, arch} = platforms[i];
|
||||
|
||||
sizeCheckInfo.push(JSON.stringify({
|
||||
'sdk': 'maps',
|
||||
'platform' : platform,
|
||||
'arch': arch,
|
||||
'size' : runSizeMeasurements[i],
|
||||
'created_at': date
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATION_ID})
|
||||
.then(({data}) => {
|
||||
github.authenticate({type: 'token', token: data.token});
|
||||
|
||||
return query().then(function() {
|
||||
// Uploads to data source used by
|
||||
// http://mapbox.github.io/mapbox-gl-native/metrics/binary-size/
|
||||
var firstPromise = new AWS.S3({region: 'us-east-1'}).putObject({
|
||||
Body: zlib.gzipSync(JSON.stringify(rows.reverse())),
|
||||
Bucket: 'mapbox',
|
||||
Key: 'mapbox-gl-native/metrics/binary-size/data.json',
|
||||
ACL: 'public-read',
|
||||
CacheControl: 'max-age=300',
|
||||
ContentEncoding: 'gzip',
|
||||
ContentType: 'application/json'
|
||||
}).promise();
|
||||
// Uploads to data source used by Mapbox internal metrics dashboards
|
||||
var secondPromise = new AWS.S3({region: 'us-east-1'}).putObject({
|
||||
Body: zlib.gzipSync(sizeCheckInfo.join('\n')),
|
||||
Bucket: 'mapbox-loading-dock',
|
||||
Key: `raw/mobile.binarysize/${date.substring(0,10)}/mapbox-maps-ios-android-${process.env['CIRCLE_SHA1']}.json.gz`,
|
||||
CacheControl: 'max-age=300',
|
||||
ContentEncoding: 'gzip',
|
||||
ContentType: 'application/json'
|
||||
}).promise();
|
||||
|
||||
return Promise.all([firstPromise, secondPromise]).then(data => {
|
||||
return console.log("Successfully uploaded all binary size metrics to S3");
|
||||
}).catch(err => {
|
||||
console.log("Error uploading binary size metrics to S3 " + err.message);
|
||||
return err;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Script to retrieve total code coverage ratio from codecov.io
|
||||
// for a given commit hash, and upload it to the S3 bucket.
|
||||
|
||||
const https = require('https');
|
||||
const zlib = require('zlib');
|
||||
const AWS = require('aws-sdk');
|
||||
const {execSync} = require('child_process');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const options = {
|
||||
help: false
|
||||
};
|
||||
|
||||
const usage = 'usage: publish_code_coverage.js [options]\n' +
|
||||
'options: \n' +
|
||||
' -h, --help \n' +
|
||||
' -p, --platform <Platform Name>\n' +
|
||||
' -s, --sdk <Sdk Name> \n' +
|
||||
' -c, --commit <Commit Hash> \n';
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
|
||||
switch(arg) {
|
||||
case '-h':
|
||||
case '--help':
|
||||
options.help = true;
|
||||
break;
|
||||
case '-s':
|
||||
case '--sdk':
|
||||
options.sdkName = args[i + 1];
|
||||
break;
|
||||
case '-p':
|
||||
case '--platform':
|
||||
options.platformName = args[i + 1];
|
||||
break;
|
||||
case '-c':
|
||||
case '--commit':
|
||||
options.commitId = args[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.help == true) {
|
||||
console.log(usage);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Commit hash
|
||||
const commitHash = options.commitId ? options.commitId : process.env['CIRCLE_SHA1'];
|
||||
if (!options.sdkName || !options.platformName || !commitHash) {
|
||||
console.log(usage);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Commit Message
|
||||
const commitMessage = execSync(`git show --pretty=format:%s -s ${commitHash}`).toString().trim();
|
||||
if (!commitMessage) {
|
||||
throw new Error ('Commit message is missing');
|
||||
}
|
||||
|
||||
const date = new Date().toISOString().substring(0, 19);
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Parse the response received from codecov.io and build the
|
||||
// data point that is going to be uploaded to S3 bucket.
|
||||
function parseResponse(data) {
|
||||
if (data && data.commit) {
|
||||
if (!data.commit.totals || !data.commit.totals.c) {
|
||||
return;
|
||||
}
|
||||
|
||||
const source = {
|
||||
code_coverage: Number(data.commit.totals.c),
|
||||
platform: options.platformName,
|
||||
sdk: options.sdkName,
|
||||
commit: commitHash,
|
||||
commit_message: commitMessage,
|
||||
created_at: date
|
||||
};
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
// Upload to data source used by Mapbox internal metrics dashboards
|
||||
function uploadData(data) {
|
||||
return new AWS.S3({region: 'us-east-1'}).putObject({
|
||||
Body: zlib.gzipSync(JSON.stringify(data)),
|
||||
Bucket: 'mapbox-loading-dock',
|
||||
Key: `raw/mobile_staging.codecoverage/${date.substring(0,10)}/${options.sdkName}-coverage-${commitHash}.json.gz`,
|
||||
CacheControl: 'max-age=300',
|
||||
ContentEncoding: 'gzip',
|
||||
ContentType: 'application/json'
|
||||
}).promise();
|
||||
}
|
||||
|
||||
// Attempt to retrieve code coverage report from codecov.io
|
||||
// for a given commit hash.
|
||||
function httpRequest() {
|
||||
const options = {
|
||||
hostname: 'codecov.io',
|
||||
port: 443,
|
||||
path: '/api/gh/mapbox/mapbox-gl-native/commit/' + commitHash,
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(function() {
|
||||
const req = https.request(options, (res) => {
|
||||
var body = [];
|
||||
res.on('data', (chunk) => {
|
||||
body.push(chunk);
|
||||
}).on('error', (error) => {
|
||||
reject(error);
|
||||
}).on('end', () => {
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
return reject(new Error('Failed to fetch coverage report from codecov.io. StatusCode=' + res.statusCode));
|
||||
}
|
||||
|
||||
try {
|
||||
body = JSON.parse(Buffer.concat(body).toString());
|
||||
resolve(body);
|
||||
} catch(e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Reject on error
|
||||
req.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
req.end();
|
||||
}, 30000);
|
||||
});
|
||||
}
|
||||
|
||||
var errResponse = false;
|
||||
const publishWithRetry = (maxRetries) => {
|
||||
httpRequest().then((body) => {
|
||||
const dataSource = parseResponse(body);
|
||||
if (dataSource) {
|
||||
return uploadData(dataSource);
|
||||
} else {
|
||||
errResponse = true;
|
||||
throw new Error('Failed to parse coverage report received from codecov.io.');
|
||||
}
|
||||
}).then(data => {
|
||||
console.log('Successfully uploaded code coverage metrics to S3');
|
||||
}).catch(err => {
|
||||
if (maxRetries > 1 && errResponse) {
|
||||
console.log('Invalid coverage report received. Trying to retrieve again.');
|
||||
errResponse = false;
|
||||
return publishWithRetry(maxRetries - 1);
|
||||
}
|
||||
|
||||
console.error('Failed to upload code coverage metrics to S3: ' + err.message);
|
||||
});
|
||||
};
|
||||
|
||||
// Fetch and publish code coverage report
|
||||
publishWithRetry(5);
|
||||
@@ -1,92 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const github = require('@octokit/rest').plugin(require('@octokit/plugin-retry'))({
|
||||
retry: { doNotRetry: [ /* Empty — retry on any error code. */ ] }
|
||||
})
|
||||
const zlib = require('zlib');
|
||||
const AWS = require('aws-sdk');
|
||||
const fs = require('fs');
|
||||
|
||||
const SIZE_CHECK_APP_ID = 14028;
|
||||
const SIZE_CHECK_APP_INSTALLATION_ID = 229425;
|
||||
|
||||
var coverage;
|
||||
|
||||
try {
|
||||
coverage = JSON.parse(fs.readFileSync(process.argv[2]));
|
||||
if (typeof coverage.documented !== 'number' || typeof coverage.total !== 'number' ||
|
||||
coverage.documented > coverage.total) {
|
||||
throw new Error('Invalid coverage.json file');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Failed to parse json file with coverage data: ', error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', error => {
|
||||
console.log(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY'];
|
||||
if (!pk) {
|
||||
console.log('Fork PR; not publishing size.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const key = Buffer.from(pk, 'base64').toString('binary');
|
||||
const payload = {
|
||||
exp: Math.floor(Date.now() / 1000) + 60,
|
||||
iat: Math.floor(Date.now() / 1000),
|
||||
iss: SIZE_CHECK_APP_ID
|
||||
};
|
||||
|
||||
const token = jwt.sign(payload, key, {algorithm: 'RS256'});
|
||||
github.authenticate({type: 'app', token});
|
||||
|
||||
github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATION_ID})
|
||||
.then(({data}) => {
|
||||
github.authenticate({type: 'token', token: data.token});
|
||||
const percentage = coverage.documented * 100 / coverage.total;
|
||||
const title = `${percentage.toFixed(2)}%`;
|
||||
const date = new Date().toISOString().substring(0, 19);
|
||||
|
||||
var promises = [github.checks.create({
|
||||
owner: 'mapbox',
|
||||
repo: 'mapbox-gl-native',
|
||||
name: 'Doxygen coverage',
|
||||
head_branch: process.env['CIRCLE_BRANCH'],
|
||||
head_sha: process.env['CIRCLE_SHA1'],
|
||||
status: 'completed',
|
||||
conclusion: 'success',
|
||||
completed_at: new Date().toISOString(),
|
||||
output: {
|
||||
title,
|
||||
summary: `There is doxygen documentation for ${percentage}% of the public symbols (${coverage.documented} out of ${coverage.total})`
|
||||
}
|
||||
})];
|
||||
|
||||
if (process.env['CIRCLE_BRANCH'] === 'main') {
|
||||
promises.push(new AWS.S3({region: 'us-east-1'}).putObject({
|
||||
Body: zlib.gzipSync(JSON.stringify({
|
||||
'created_at': date,
|
||||
'documented': coverage.documented,
|
||||
'total': coverage.total,
|
||||
'commit': process.env['CIRCLE_SHA1']
|
||||
})),
|
||||
Bucket: 'mapbox-loading-dock',
|
||||
Key: `raw/mobile_staging.docs_coverage/${date.substring(0,10)}/${process.env['CIRCLE_SHA1']}.json.gz`,
|
||||
CacheControl: 'max-age=300',
|
||||
ContentEncoding: 'gzip',
|
||||
ContentType: 'application/json'
|
||||
}).promise());
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(data => {
|
||||
return console.log('Succesfully uploaded doxygen coverage metrics');
|
||||
}).catch(err => {
|
||||
console.log('Error uploading doxygen coverage metrics: ' + err.message);
|
||||
return err;
|
||||
});
|
||||
});
|
||||
@@ -1,147 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const assert = require('assert');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const github = require('@octokit/rest')();
|
||||
const zlib = require('zlib');
|
||||
const AWS = require('aws-sdk');
|
||||
|
||||
const SIZE_CHECK_APP_ID = 14028;
|
||||
const SIZE_CHECK_APP_INSTALLATION_ID = 229425;
|
||||
|
||||
// Error handling
|
||||
|
||||
process.on('unhandledRejection', error => {
|
||||
console.log(error);
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
// Github authorization
|
||||
|
||||
const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY'];
|
||||
if (!pk) {
|
||||
console.log('Fork PR; not publishing size.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const key = Buffer.from(pk, 'base64').toString('binary');
|
||||
const payload = {
|
||||
exp: Math.floor(Date.now() / 1000) + 60,
|
||||
iat: Math.floor(Date.now() / 1000),
|
||||
iss: SIZE_CHECK_APP_ID
|
||||
};
|
||||
|
||||
const token = jwt.sign(payload, key, {algorithm: 'RS256'});
|
||||
github.authenticate({type: 'app', token});
|
||||
|
||||
// Metrics: Github statistics
|
||||
let openIssuesTotal = 0;
|
||||
let openIssuesTotalFromNonMembers = 0;
|
||||
let openIssuesTotalCore = 0;
|
||||
let openIssuesTotalAndroid = 0;
|
||||
let openIssuesTotalIOS = 0;
|
||||
let openIssuesTotalGLJSParity = 0;
|
||||
let openPullRequestsTotal = 0;
|
||||
let openPullRequestsTotalFromNonMembers = 0;
|
||||
let openPullRequestsSinceLastMonth = 0;
|
||||
let openPullRequestsSinceLastMonthFromNonMembers = 0;
|
||||
|
||||
function collectMetricsFromIssues(issues) {
|
||||
const oneMonthAgo = function() { let date = new Date(); date.setMonth(date.getMonth() - 1); return date; }();
|
||||
|
||||
// Metrics
|
||||
issues.data.forEach(function (issue) {
|
||||
const issueCreatedAt = new Date(issue.created_at);
|
||||
const isMapboxAuthor = issue.author_association === "MEMBER";
|
||||
|
||||
if (issue.pull_request) {
|
||||
openPullRequestsTotal++;
|
||||
if (!isMapboxAuthor) {
|
||||
openPullRequestsTotalFromNonMembers++;
|
||||
}
|
||||
if (issueCreatedAt >= oneMonthAgo) {
|
||||
openPullRequestsSinceLastMonth++;
|
||||
if (!isMapboxAuthor) {
|
||||
openPullRequestsSinceLastMonthFromNonMembers++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
openIssuesTotal++;
|
||||
if (!isMapboxAuthor) {
|
||||
openIssuesTotalFromNonMembers++;
|
||||
}
|
||||
issue.labels.forEach(function (label) {
|
||||
switch (label.name) {
|
||||
case "Core":
|
||||
openIssuesTotalCore++;
|
||||
break;
|
||||
case "Android":
|
||||
openIssuesTotalAndroid++;
|
||||
break;
|
||||
case "iOS":
|
||||
openIssuesTotalIOS++;
|
||||
break;
|
||||
case "GL JS parity":
|
||||
openIssuesTotalGLJSParity++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function publishMetrics() {
|
||||
let metrics = {
|
||||
'created_at': new Date().toISOString().substring(0, 10),
|
||||
'open_issues_total': openIssuesTotal,
|
||||
'open_issues_total_from_non_members': openIssuesTotalFromNonMembers,
|
||||
'open_issues_total_core': openIssuesTotalCore,
|
||||
'open_issues_total_android': openIssuesTotalAndroid,
|
||||
'open_issues_total_ios': openIssuesTotalIOS,
|
||||
'open_issues_total_gl_js_parity': openIssuesTotalGLJSParity,
|
||||
'open_pull_requests_total': openPullRequestsTotal,
|
||||
'open_pull_requests_total_from_non_members': openPullRequestsTotalFromNonMembers,
|
||||
'open_pull_requests_since_last_month': openPullRequestsSinceLastMonth,
|
||||
'open_pull_requests_since_last_month_from_non_members': openPullRequestsSinceLastMonthFromNonMembers
|
||||
};
|
||||
|
||||
var promise = new AWS.S3({region: 'us-east-1'}).putObject({
|
||||
Body: zlib.gzipSync(JSON.stringify(metrics)),
|
||||
Bucket: 'mapbox-loading-dock',
|
||||
Key: `raw/mobile_staging.github_stats/${metrics['created_at']}/METRIC.json.gz`,
|
||||
CacheControl: 'max-age=300',
|
||||
ContentEncoding: 'gzip',
|
||||
ContentType: 'application/json'
|
||||
}).promise();
|
||||
|
||||
return Promise.all([promise]).then(data => {
|
||||
return console.log("Successfully uploaded Github Stats metrics to S3");
|
||||
}).catch(err => {
|
||||
console.log("Error uploading Github Stats metrics to S3 " + err.message);
|
||||
return err;
|
||||
});
|
||||
}
|
||||
|
||||
function recursiveListForRepo(query) {
|
||||
assert(query);
|
||||
query.then(result => {
|
||||
collectMetricsFromIssues(result);
|
||||
if (github.hasNextPage(result)) {
|
||||
recursiveListForRepo(github.getNextPage(result));
|
||||
} else {
|
||||
publishMetrics();
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log("Error fetching the repository issues list: " + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
github.apps.createInstallationToken({ installation_id: SIZE_CHECK_APP_INSTALLATION_ID })
|
||||
.then(({data}) => {
|
||||
github.authenticate({ type: 'token', token: data.token });
|
||||
})
|
||||
.then(() => {
|
||||
recursiveListForRepo(github.issues.listForRepo({ owner: 'mapbox', repo: 'mapbox-gl-native', state: 'open', per_page: 100 }));
|
||||
});
|
||||
@@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
|
||||
function usage {
|
||||
echo "Usage: $0 <args> [target]"
|
||||
echo ""
|
||||
echo " -c, --clean-target Removes all files in the target directory instead of overwriting them"
|
||||
echo " -s, --skip [name] Skips vendoring the given dependency"
|
||||
exit 1
|
||||
}
|
||||
|
||||
CLEAN_TARGET=false
|
||||
|
||||
ARGS=()
|
||||
while [[ $# -gt 0 ]] ; do case "$1" in
|
||||
-c|--clean-target) CLEAN_TARGET=true ; shift ;;
|
||||
-s|--skip) shift ; DEP="$1" ; shift ; declare SKIP_$DEP=true ;;
|
||||
*) ARGS+=("$1") ; shift ;;
|
||||
esac ; done
|
||||
set -- "${ARGS[@]}"
|
||||
|
||||
if [ -z "$1" ]; then usage ; fi
|
||||
TARGET="$1"
|
||||
|
||||
if [ "$CLEAN_TARGET" = true ] ; then
|
||||
echo ">> Cleaning target directory..."
|
||||
rm -rf "$TARGET"
|
||||
fi
|
||||
|
||||
echo ">> Creating target directory..."
|
||||
mkdir -p "$TARGET"
|
||||
TARGET=$(cd "`pwd`/$TARGET"; pwd)
|
||||
|
||||
echo ">> Creating file lists..."
|
||||
cat cmake/core-files.txt cmake/filesource-files.txt > "$TARGET/files.txt"
|
||||
mkdir -p "$TARGET/platform/android"
|
||||
cat platform/android/*-files.txt > "$TARGET/platform/android/files.txt"
|
||||
|
||||
echo ">> Copying source files..."
|
||||
rsync -rR $(git ls-files \
|
||||
"include" \
|
||||
"src" \
|
||||
"platform/default" \
|
||||
"platform/android/mbgl" \
|
||||
"platform/android/src" \
|
||||
"platform/linux/src" \
|
||||
"platform/android/MapboxGLAndroidSDK/src/main" \
|
||||
) "$TARGET"
|
||||
|
||||
echo ">> Copying vendored files..."
|
||||
rsync -rR $(git ls-files \
|
||||
"vendor/expected" \
|
||||
"vendor/icu" \
|
||||
"vendor/nunicode" \
|
||||
"vendor/sqlite" \
|
||||
) "$TARGET"
|
||||
|
||||
echo ">> Copying Mason dependencies..."
|
||||
cmake -P scripts/standalone.cmake 2>&1 | while read DEPENDENCY ; do
|
||||
DEPENDENCY=($DEPENDENCY)
|
||||
if [ "[Mason]" = "${DEPENDENCY[0]}" ]; then
|
||||
echo "${DEPENDENCY[@]}"
|
||||
continue
|
||||
fi
|
||||
SKIP=SKIP_${DEPENDENCY[0]}
|
||||
if [ "${!SKIP:-false}" = true ]; then continue ; fi
|
||||
DESTINATION="$TARGET/vendor/${DEPENDENCY[0]}"
|
||||
mkdir -p "$DESTINATION"
|
||||
echo " - ${DEPENDENCY[0]}"
|
||||
cp -r "${DEPENDENCY[1]}/" "$DESTINATION"
|
||||
rm "$DESTINATION/mason.ini"
|
||||
(cd "${DEPENDENCY[1]}" && find include -type f -name "*.hpp" -o -name "*.h") > "$DESTINATION/files.txt"
|
||||
echo "${DEPENDENCY[2]}" > "$DESTINATION/version.txt"
|
||||
done
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
|
||||
function finish { >&2 echo -en "\033[0m"; }
|
||||
trap finish EXIT
|
||||
|
||||
SDK_FLAVOR=${SDK_FLAVOR:-"maps"}
|
||||
|
||||
step "Triggering automated site and documentation generation for ${SDK_FLAVOR} SDK ${VERSION_TAG}"
|
||||
|
||||
# No branch specified, so default branch will be used
|
||||
request_body="{
|
||||
\"request\": {
|
||||
\"message\": \"[${SDK_FLAVOR}] ${VERSION_TAG} automated site and documentation generation\",
|
||||
\"config\": {
|
||||
\"merge_mode\": \"deep_merge\",
|
||||
\"env\": {
|
||||
\"SDK_FLAVOR\": \"${SDK_FLAVOR}\",
|
||||
\"RELEASE_TAG\": \"${VERSION_TAG}\"
|
||||
}
|
||||
}
|
||||
}
|
||||
}"
|
||||
|
||||
step "Making request…"
|
||||
|
||||
# Request URL set to docs-sandbox while testing
|
||||
curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Travis-API-Version: 3" \
|
||||
-H "Authorization: token ${TRAVISCI_API_TOKEN}" \
|
||||
-d "${request_body}" \
|
||||
https://api.travis-ci.com/repo/mapbox%2F${DOCS_REPO}/requests
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
pushd "$BOOST"
|
||||
if [ ! -f dist/bin/bcp ]; then
|
||||
# Build bcp
|
||||
./bootstrap.sh
|
||||
./b2 tools/bcp
|
||||
fi
|
||||
popd
|
||||
|
||||
# Extract boost modules that we need
|
||||
rm -rf vendor/boost/include
|
||||
mkdir -p vendor/boost/include
|
||||
"$BOOST/dist/bin/bcp" --boost="$BOOST" --scan $(find {src,include,test,platform,bin} -name "*.cpp" -o -name "*.hpp") vendor/boost/include
|
||||
|
||||
pushd vendor/boost
|
||||
VERSION=$(sed -n 's/^#define BOOST_LIB_VERSION "\([^"]*\)"$/\1/p' include/boost/version.hpp)
|
||||
echo "libboost ${VERSION/_/.} for Mapbox GL Native" > README.md
|
||||
git add README.md include
|
||||
popd
|
||||
|
||||
echo "If everything works, run:"
|
||||
echo ""
|
||||
echo " git -C vendor/boost checkout main"
|
||||
echo " git -C vendor/boost commit -m \"update boost to ${VERSION/_/.}\""
|
||||
echo " git -C vendor/boost push"
|
||||
echo " git add vendor/boost"
|
||||
echo ""
|
||||
echo "and commit."
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd misc
|
||||
curl https://raw.githubusercontent.com/curl/curl/master/lib/mk-ca-bundle.pl | perl
|
||||
rm certdata.txt
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
VALGRIND_PREFIX=$(scripts/mason.sh PREFIX valgrind VERSION 3.12.0)
|
||||
|
||||
PARAMS="\
|
||||
--leak-check=full \
|
||||
--show-leak-kinds=definite \
|
||||
--errors-for-leak-kinds=definite \
|
||||
--error-exitcode=1 \
|
||||
--gen-suppressions=all \
|
||||
--suppressions=scripts/valgrind.sup"
|
||||
|
||||
export VALGRIND_LIB=${VALGRIND_PREFIX}/lib/valgrind
|
||||
|
||||
${VALGRIND_PREFIX}/bin/valgrind $PARAMS $@
|
||||
@@ -1,78 +0,0 @@
|
||||
{
|
||||
Graphics driver bugs
|
||||
Memcheck:Cond
|
||||
...
|
||||
obj:*/swrast_dri.*
|
||||
obj:*/swrast_dri.*
|
||||
obj:*/swrast_dri.*
|
||||
...
|
||||
}
|
||||
{
|
||||
Graphics driver bugs
|
||||
Memcheck:Value8
|
||||
...
|
||||
obj:*/swrast_dri.*
|
||||
obj:*/swrast_dri.*
|
||||
obj:*/swrast_dri.*
|
||||
...
|
||||
}
|
||||
{
|
||||
Ubuntu 16.04 - Mysterious leak when running utests
|
||||
Memcheck:Leak
|
||||
fun:calloc
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
obj:*
|
||||
}
|
||||
{
|
||||
Qt5
|
||||
Memcheck:Cond
|
||||
...
|
||||
obj:*/libQt5Core.*
|
||||
...
|
||||
}
|
||||
{
|
||||
Qt5
|
||||
Memcheck:Value8
|
||||
...
|
||||
obj:*/libQt5Core.*
|
||||
...
|
||||
}
|
||||
{
|
||||
Qt5
|
||||
Memcheck:Cond
|
||||
...
|
||||
obj:*/libQt5Gui.*
|
||||
...
|
||||
}
|
||||
{
|
||||
Qt5
|
||||
Memcheck:Value8
|
||||
...
|
||||
obj:*/libQt5Gui.*
|
||||
...
|
||||
}
|
||||
{
|
||||
mapbox::pixelmatch
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:_ZN6mapbox10pixelmatchEPKhS1_mmPhdb
|
||||
...
|
||||
}
|
||||
{
|
||||
util::write_file
|
||||
Memcheck:Param
|
||||
write(buf)
|
||||
...
|
||||
obj:*/libc-*
|
||||
fun:_ZN4mbgl4util10write_fileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_
|
||||
...
|
||||
}
|
||||
39
platform/ios/scripts/vendor/common.sh
vendored
39
platform/ios/scripts/vendor/common.sh
vendored
@@ -1,39 +0,0 @@
|
||||
|
||||
set -eu
|
||||
|
||||
VENDOR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../../vendor"; pwd)
|
||||
CXX=${CXX:-clang++}
|
||||
CC=${CC:-clang}
|
||||
|
||||
function download {
|
||||
if [ ! -f "$VENDOR/.cache/$NAME-$VERSION" ]; then
|
||||
echo ">> Downloading $1..."
|
||||
mkdir -p "$VENDOR/.cache"
|
||||
curl --retry 3 -f -S -L $1 -o "$VENDOR/.cache/$NAME-$VERSION.tmp"
|
||||
mv "$VENDOR/.cache/$NAME-$VERSION.tmp" "$VENDOR/.cache/$NAME-$VERSION"
|
||||
fi
|
||||
}
|
||||
|
||||
function init {
|
||||
rm -rf "$VENDOR/$NAME"
|
||||
mkdir -p "$VENDOR/$NAME"
|
||||
echo $VERSION > "$VENDOR/$NAME/version.txt"
|
||||
cd "$VENDOR/$NAME"
|
||||
}
|
||||
|
||||
function extract_gzip {
|
||||
echo ">> Unpacking files from $VENDOR/.cache/$NAME-$VERSION..."
|
||||
[ ! -z "$(tar --version | grep "GNU tar")" ] && WC="--wildcards" || WC=""
|
||||
tar xzf "$VENDOR/.cache/$NAME-$VERSION" $WC --strip-components=${STRIP_COMPONENTS:-1} -C "$VENDOR/$NAME" $@
|
||||
}
|
||||
|
||||
function extract_zip {
|
||||
echo ">> Unpacking files from $VENDOR/.cache/$NAME-$VERSION..."
|
||||
unzip -qq "$VENDOR/.cache/$NAME-$VERSION" $@ -d "$VENDOR/.cache/staging"
|
||||
mv "$VENDOR/.cache/staging"/*/* "$VENDOR/$NAME"
|
||||
rm -rf "$VENDOR/.cache/staging"
|
||||
}
|
||||
|
||||
function file_list {
|
||||
(cd "$VENDOR/$NAME" && find $@ | LC_ALL=C sort > "$VENDOR/$NAME/files.txt")
|
||||
}
|
||||
13
platform/ios/scripts/vendor/expected.sh
vendored
13
platform/ios/scripts/vendor/expected.sh
vendored
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
||||
|
||||
NAME=expected
|
||||
VERSION=a2359cf61478d735a308e952b1c9840714f61386
|
||||
ROOT=expected-lite-$VERSION
|
||||
|
||||
download "https://github.com/martinmoene/expected-lite/archive/$VERSION.tar.gz"
|
||||
init
|
||||
extract_gzip "$ROOT/include" "$ROOT/LICENSE.txt"
|
||||
mv include/nonstd/expected.hpp include
|
||||
rm -rf include/nonstd
|
||||
file_list include -name "*.hpp"
|
||||
72
platform/ios/scripts/vendor/icu.sh
vendored
72
platform/ios/scripts/vendor/icu.sh
vendored
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
||||
|
||||
NAME=icu
|
||||
VERSION=61.1
|
||||
ROOT=icu/source
|
||||
|
||||
download "http://download.icu-project.org/files/icu4c/$VERSION/icu4c-${VERSION//./_}-src.tgz"
|
||||
init
|
||||
STRIP_COMPONENTS=2 extract_gzip "${ROOT}/common/*.h" "${ROOT}/common/*.cpp"
|
||||
STRIP_COMPONENTS=1 extract_gzip "icu/LICENSE"
|
||||
|
||||
# List all files we want to extract
|
||||
FILES=(
|
||||
ushape.cpp
|
||||
ubidi.cpp
|
||||
ubidi_props.cpp
|
||||
ubidiln.cpp
|
||||
ubidiwrt.cpp
|
||||
ustring.cpp
|
||||
uinvchar.cpp
|
||||
uchar.cpp
|
||||
udataswp.cpp
|
||||
umath.cpp
|
||||
utrie2.cpp
|
||||
utf_impl.cpp
|
||||
utypes.cpp
|
||||
cmemory.cpp
|
||||
cstring.cpp
|
||||
)
|
||||
|
||||
# Find dependencies for all of these files
|
||||
echo ">> Finding dependencies..."
|
||||
ALL=()
|
||||
for FILE in "${FILES[@]}"; do
|
||||
ALL+=($(cd "common" && $CXX -std=c++14 -I. -c "$FILE" -M | sed -e 's/^[a-z0-9._-]*: *//;s/ *\\$//'))
|
||||
done
|
||||
|
||||
# Remove duplicates
|
||||
IFS=$'\n' ALL=($(sort <<< "${ALL[*]}" | uniq | sed '/^\//d'))
|
||||
unset IFS
|
||||
|
||||
echo ">> Copying files..."
|
||||
mkdir -p src include/unicode
|
||||
for FILE in "${ALL[@]}"; do
|
||||
[[ "$FILE" = unicode/* ]] && DIR="include" || DIR="src"
|
||||
# Copy file and replace #include "unicode/*" with #include <unicode/*> so that we can separate
|
||||
# includes and source-only files.
|
||||
sed 's/^#include \"\(unicode\/[^\"]\{1,\}\)\"/#include <\1>/' "common/$FILE" > "$DIR/$FILE"
|
||||
done
|
||||
|
||||
# Apply patch from https://github.com/LibreOffice/core/blob/master/external/icu/icu4c-ubsan.patch.1
|
||||
# Shifting signed int to a number greater than can be represented is undefined behavior
|
||||
patch -p0 << PATCH
|
||||
--- src/ubidiimp.h
|
||||
+++ src/ubidiimp.h
|
||||
@@ -198,8 +198,8 @@
|
||||
/* in a Run, logicalStart will get this bit set if the run level is odd */
|
||||
#define INDEX_ODD_BIT (1UL<<31)
|
||||
|
||||
-#define MAKE_INDEX_ODD_PAIR(index, level) ((index)|((int32_t)(level)<<31))
|
||||
+#define MAKE_INDEX_ODD_PAIR(index, level) ((index)|((uint32_t)(level)<<31))
|
||||
-#define ADD_ODD_BIT_FROM_LEVEL(x, level) ((x)|=((int32_t)(level)<<31))
|
||||
+#define ADD_ODD_BIT_FROM_LEVEL(x, level) ((x)|=((uint32_t)(level)<<31))
|
||||
#define REMOVE_ODD_BIT(x) ((x)&=~INDEX_ODD_BIT)
|
||||
|
||||
#define GET_INDEX(x) ((x)&~INDEX_ODD_BIT)
|
||||
PATCH
|
||||
|
||||
rm -rf common
|
||||
|
||||
file_list include src -name "*.h" -o -name "*.cpp"
|
||||
70
platform/ios/scripts/vendor/nunicode.sh
vendored
70
platform/ios/scripts/vendor/nunicode.sh
vendored
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
||||
|
||||
NAME=nunicode
|
||||
VERSION=1.8
|
||||
ROOT=alekseyt-nunicode-246bb27014ab
|
||||
|
||||
download "https://bitbucket.org/alekseyt/nunicode/get/$VERSION.tar.gz"
|
||||
init
|
||||
extract_gzip "$ROOT/libnu/*.c" "$ROOT/libnu/*.h" "$ROOT/LICENSE"
|
||||
|
||||
# Augment config.h with just the defines we need.
|
||||
head -n 2 libnu/config.h > config.h
|
||||
cat <<CONFIG >> config.h
|
||||
|
||||
// Hardcoded defines for vendored copy
|
||||
#define NU_WITH_UTF8
|
||||
#define NU_WITH_TOUPPER
|
||||
#define NU_WITH_TOLOWER
|
||||
#define NU_WITH_UNACCENT
|
||||
#define NU_WITH_Z_COLLATION
|
||||
CONFIG
|
||||
tail -n +3 libnu/config.h >> config.h
|
||||
mv config.h libnu/config.h
|
||||
|
||||
# List all files we want to extract
|
||||
FILES=(
|
||||
libnu/strcoll.h
|
||||
libnu/strcoll.c
|
||||
|
||||
libnu/ducet.h
|
||||
libnu/ducet.c
|
||||
|
||||
libnu/unaccent.h
|
||||
libnu/tounaccent.c
|
||||
|
||||
libnu/casemap.h
|
||||
libnu/toupper.c
|
||||
libnu/tolower.c
|
||||
|
||||
libnu/strings.h
|
||||
libnu/strings.c
|
||||
|
||||
libnu/utf8.h
|
||||
libnu/utf8.c
|
||||
)
|
||||
|
||||
# Find dependencies for all of these files
|
||||
echo ">> Finding dependencies..."
|
||||
ALL=()
|
||||
for FILE in "${FILES[@]}"; do
|
||||
ALL+=($($CC -std=c11 -Ilibnu -c "$FILE" -M | sed -e 's/^[a-z0-9._-]*: *//;s/ *\\$//'))
|
||||
done
|
||||
|
||||
# Remove duplicates
|
||||
IFS=$'\n' ALL=($(sort <<< "${ALL[*]}" | uniq | sed -n '/^libnu\//p'))
|
||||
unset IFS
|
||||
|
||||
echo ">> Copying files..."
|
||||
|
||||
mkdir -p include/libnu src/libnu/gen
|
||||
for FILE in "${ALL[@]}"; do
|
||||
[[ "$FILE" = *.h ]] && DIR="include" || DIR="src"
|
||||
# Copy file and replace #include "*.h" with #include <libnu/*.h> so that we can separate
|
||||
# includes and source-only files.
|
||||
sed 's/^#include \"\([^\"]*.h\)\"/#include <libnu\/\1>/' "$FILE" > "$DIR/$FILE"
|
||||
done
|
||||
|
||||
rm -rf libnu
|
||||
file_list include src -name "*.h" -o -name "*.c" -not -path "*/gen/*"
|
||||
14
platform/ios/scripts/vendor/sqlite.sh
vendored
14
platform/ios/scripts/vendor/sqlite.sh
vendored
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/common.sh"
|
||||
|
||||
NAME=sqlite
|
||||
VERSION=3.24.0
|
||||
ROOT=sqlite-amalgamation-3240000
|
||||
|
||||
download "https://www.sqlite.org/2018/$ROOT.zip"
|
||||
init
|
||||
extract_zip "$ROOT/sqlite3.*"
|
||||
mkdir -p include src
|
||||
mv sqlite3.h include
|
||||
mv sqlite3.c src
|
||||
file_list include src -name "*.h" -o -name "*.c"
|
||||
Reference in New Issue
Block a user