mirror of
https://gitee.com/openharmony/third_party_littlefs
synced 2024-11-23 14:59:50 +00:00
0990296619
Byte-level writes are expensive and not suggested (caches >= 4 bytes make much more sense), however there are many corner cases with byte-level writes that can be easy to miss (power-loss leaving single bytes written to disk). Unfortunately, byte-level writes mixed with power-loss testing, the Travis infrastructure, and Arm Thumb instruction set simulation exceeds the 50-minute budget Travis allocates for jobs. For now I'm disabling the byte-level tests under Qemu, with the hope that performance improvements in littlefs will let us turn these tests back on in the future.
430 lines
16 KiB
YAML
430 lines
16 KiB
YAML
# environment variables
|
|
env:
|
|
global:
|
|
- CFLAGS=-Werror
|
|
- MAKEFLAGS=-j
|
|
|
|
# cache installation dirs
|
|
cache:
|
|
pip: true
|
|
directories:
|
|
- $HOME/.cache/apt
|
|
|
|
# common installation
|
|
_: &install-common
|
|
# need toml, also pip3 isn't installed by default?
|
|
- sudo apt-get install python3 python3-pip
|
|
- sudo pip3 install toml
|
|
# setup a ram-backed disk to speed up reentrant tests
|
|
- mkdir disks
|
|
- sudo mount -t tmpfs -o size=100m tmpfs disks
|
|
- export TFLAGS="$TFLAGS --disk=disks/disk"
|
|
|
|
# test cases
|
|
_: &test-example
|
|
# make sure example can at least compile
|
|
- sed -n '/``` c/,/```/{/```/d; p}' README.md > test.c &&
|
|
make all CFLAGS+="
|
|
-Duser_provided_block_device_read=NULL
|
|
-Duser_provided_block_device_prog=NULL
|
|
-Duser_provided_block_device_erase=NULL
|
|
-Duser_provided_block_device_sync=NULL
|
|
-include stdio.h"
|
|
# default tests
|
|
_: &test-default
|
|
# normal+reentrant tests
|
|
- make test TFLAGS+="-nrk"
|
|
# common real-life geometries
|
|
_: &test-nor
|
|
# NOR flash: read/prog = 1 block = 4KiB
|
|
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096"
|
|
_: &test-emmc
|
|
# eMMC: read/prog = 512 block = 512
|
|
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512"
|
|
_: &test-nand
|
|
# NAND flash: read/prog = 4KiB block = 32KiB
|
|
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)"
|
|
# other extreme geometries that are useful for testing various corner cases
|
|
_: &test-no-intrinsics
|
|
- make test TFLAGS+="-nrk -DLFS_NO_INTRINSICS"
|
|
_: &test-no-inline
|
|
- make test TFLAGS+="-nrk -DLFS_INLINE_MAX=0"
|
|
_: &test-byte-writes
|
|
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1"
|
|
_: &test-block-cycles
|
|
- make test TFLAGS+="-nrk -DLFS_BLOCK_CYCLES=1"
|
|
_: &test-odd-block-count
|
|
- make test TFLAGS+="-nrk -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256"
|
|
_: &test-odd-block-size
|
|
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704"
|
|
|
|
# report size
|
|
_: &report-size
|
|
# compile and find the code size with the smallest configuration
|
|
- make -j1 clean size
|
|
OBJ="$(ls lfs*.c | sed 's/\.c/\.o/' | tr '\n' ' ')"
|
|
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
|
|
| tee sizes
|
|
# update status if we succeeded, compare with master if possible
|
|
- |
|
|
if [ "$TRAVIS_TEST_RESULT" -eq 0 ]
|
|
then
|
|
CURR=$(tail -n1 sizes | awk '{print $1}')
|
|
PREV=$(curl -u "$GEKY_BOT_STATUSES" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \
|
|
| jq -re "select(.sha != \"$TRAVIS_COMMIT\")
|
|
| .statuses[] | select(.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\").description
|
|
| capture(\"code size is (?<size>[0-9]+)\").size" \
|
|
|| echo 0)
|
|
|
|
STATUS="Passed, code size is ${CURR}B"
|
|
if [ "$PREV" -ne 0 ]
|
|
then
|
|
STATUS="$STATUS ($(python -c "print '%+.2f' % (100*($CURR-$PREV)/$PREV.0)")%)"
|
|
fi
|
|
fi
|
|
|
|
# stage control
|
|
stages:
|
|
- name: test
|
|
- name: deploy
|
|
if: branch = master AND type = push
|
|
|
|
# job control
|
|
jobs:
|
|
# native testing
|
|
- &x86
|
|
stage: test
|
|
env:
|
|
- NAME=littlefs-x86
|
|
install: *install-common
|
|
script: [*test-example, *report-size]
|
|
- {<<: *x86, script: [*test-default, *report-size]}
|
|
- {<<: *x86, script: [*test-nor, *report-size]}
|
|
- {<<: *x86, script: [*test-emmc, *report-size]}
|
|
- {<<: *x86, script: [*test-nand, *report-size]}
|
|
- {<<: *x86, script: [*test-no-intrinsics, *report-size]}
|
|
- {<<: *x86, script: [*test-no-inline, *report-size]}
|
|
- {<<: *x86, script: [*test-byte-writes, *report-size]}
|
|
- {<<: *x86, script: [*test-block-cycles, *report-size]}
|
|
- {<<: *x86, script: [*test-odd-block-count, *report-size]}
|
|
- {<<: *x86, script: [*test-odd-block-size, *report-size]}
|
|
|
|
# cross-compile with ARM (thumb mode)
|
|
- &arm
|
|
stage: test
|
|
env:
|
|
- NAME=littlefs-arm
|
|
- CC="arm-linux-gnueabi-gcc --static -mthumb"
|
|
- TFLAGS="$TFLAGS --exec=qemu-arm"
|
|
install:
|
|
- *install-common
|
|
- sudo apt-get install
|
|
gcc-arm-linux-gnueabi
|
|
libc6-dev-armel-cross
|
|
qemu-user
|
|
- arm-linux-gnueabi-gcc --version
|
|
- qemu-arm -version
|
|
script: [*test-example, *report-size]
|
|
- {<<: *arm, script: [*test-default, *report-size]}
|
|
- {<<: *arm, script: [*test-nor, *report-size]}
|
|
- {<<: *arm, script: [*test-emmc, *report-size]}
|
|
- {<<: *arm, script: [*test-nand, *report-size]}
|
|
- {<<: *arm, script: [*test-no-intrinsics, *report-size]}
|
|
- {<<: *arm, script: [*test-no-inline, *report-size]}
|
|
# it just takes way to long to run byte-level writes in qemu,
|
|
# note this is still tested in the native tests
|
|
#- {<<: *arm, script: [*test-byte-writes, *report-size]}
|
|
- {<<: *arm, script: [*test-block-cycles, *report-size]}
|
|
- {<<: *arm, script: [*test-odd-block-count, *report-size]}
|
|
- {<<: *arm, script: [*test-odd-block-size, *report-size]}
|
|
|
|
# cross-compile with MIPS
|
|
- &mips
|
|
stage: test
|
|
env:
|
|
- NAME=littlefs-mips
|
|
- CC="mips-linux-gnu-gcc --static"
|
|
- TFLAGS="$TFLAGS --exec=qemu-mips"
|
|
install:
|
|
- *install-common
|
|
- sudo apt-get install
|
|
gcc-mips-linux-gnu
|
|
libc6-dev-mips-cross
|
|
qemu-user
|
|
- mips-linux-gnu-gcc --version
|
|
- qemu-mips -version
|
|
script: [*test-example, *report-size]
|
|
- {<<: *mips, script: [*test-default, *report-size]}
|
|
- {<<: *mips, script: [*test-nor, *report-size]}
|
|
- {<<: *mips, script: [*test-emmc, *report-size]}
|
|
- {<<: *mips, script: [*test-nand, *report-size]}
|
|
- {<<: *mips, script: [*test-no-intrinsics, *report-size]}
|
|
- {<<: *mips, script: [*test-no-inline, *report-size]}
|
|
# it just takes way to long to run byte-level writes in qemu,
|
|
# note this is still tested in the native tests
|
|
#- {<<: *mips, script: [*test-byte-writes, *report-size]}
|
|
- {<<: *mips, script: [*test-block-cycles, *report-size]}
|
|
- {<<: *mips, script: [*test-odd-block-count, *report-size]}
|
|
- {<<: *mips, script: [*test-odd-block-size, *report-size]}
|
|
|
|
# cross-compile with PowerPC
|
|
- &powerpc
|
|
stage: test
|
|
env:
|
|
- NAME=littlefs-powerpc
|
|
- CC="powerpc-linux-gnu-gcc --static"
|
|
- TFLAGS="$TFLAGS --exec=qemu-ppc"
|
|
install:
|
|
- *install-common
|
|
- sudo apt-get install
|
|
gcc-powerpc-linux-gnu
|
|
libc6-dev-powerpc-cross
|
|
qemu-user
|
|
- powerpc-linux-gnu-gcc --version
|
|
- qemu-ppc -version
|
|
script: [*test-example, *report-size]
|
|
- {<<: *powerpc, script: [*test-default, *report-size]}
|
|
- {<<: *powerpc, script: [*test-nor, *report-size]}
|
|
- {<<: *powerpc, script: [*test-emmc, *report-size]}
|
|
- {<<: *powerpc, script: [*test-nand, *report-size]}
|
|
- {<<: *powerpc, script: [*test-no-intrinsics, *report-size]}
|
|
- {<<: *powerpc, script: [*test-no-inline, *report-size]}
|
|
# it just takes way to long to run byte-level writes in qemu,
|
|
# note this is still tested in the native tests
|
|
#- {<<: *powerpc, script: [*test-byte-writes, *report-size]}
|
|
- {<<: *powerpc, script: [*test-block-cycles, *report-size]}
|
|
- {<<: *powerpc, script: [*test-odd-block-count, *report-size]}
|
|
- {<<: *powerpc, script: [*test-odd-block-size, *report-size]}
|
|
|
|
# test under valgrind, checking for memory errors
|
|
- &valgrind
|
|
stage: test
|
|
env:
|
|
- NAME=littlefs-valgrind
|
|
install:
|
|
- *install-common
|
|
- sudo apt-get install valgrind
|
|
- valgrind --version
|
|
script:
|
|
- make test TFLAGS+="-k --valgrind"
|
|
|
|
# self-host with littlefs-fuse for fuzz test
|
|
- stage: test
|
|
env:
|
|
- NAME=littlefs-fuse
|
|
if: branch !~ -prefix$
|
|
install:
|
|
- *install-common
|
|
- sudo apt-get install libfuse-dev
|
|
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2
|
|
- fusermount -V
|
|
- gcc --version
|
|
|
|
# setup disk for littlefs-fuse
|
|
- rm -rf littlefs-fuse/littlefs/*
|
|
- cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
|
|
|
|
- mkdir mount
|
|
- sudo chmod a+rw /dev/loop0
|
|
- dd if=/dev/zero bs=512 count=128K of=disk
|
|
- losetup /dev/loop0 disk
|
|
script:
|
|
# self-host test
|
|
- make -C littlefs-fuse
|
|
|
|
- littlefs-fuse/lfs --format /dev/loop0
|
|
- littlefs-fuse/lfs /dev/loop0 mount
|
|
|
|
- ls mount
|
|
- mkdir mount/littlefs
|
|
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
|
|
- cd mount/littlefs
|
|
- stat .
|
|
- ls -flh
|
|
- make -B test
|
|
|
|
# test migration using littlefs-fuse
|
|
- stage: test
|
|
env:
|
|
- NAME=littlefs-migration
|
|
if: branch !~ -prefix$
|
|
install:
|
|
- *install-common
|
|
- sudo apt-get install libfuse-dev
|
|
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2
|
|
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1
|
|
- fusermount -V
|
|
- gcc --version
|
|
|
|
# setup disk for littlefs-fuse
|
|
- rm -rf v2/littlefs/*
|
|
- cp -r $(git ls-tree --name-only HEAD) v2/littlefs
|
|
|
|
- mkdir mount
|
|
- sudo chmod a+rw /dev/loop0
|
|
- dd if=/dev/zero bs=512 count=128K of=disk
|
|
- losetup /dev/loop0 disk
|
|
script:
|
|
# compile v1 and v2
|
|
- make -C v1
|
|
- make -C v2
|
|
|
|
# run self-host test with v1
|
|
- v1/lfs --format /dev/loop0
|
|
- v1/lfs /dev/loop0 mount
|
|
|
|
- ls mount
|
|
- mkdir mount/littlefs
|
|
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
|
|
- cd mount/littlefs
|
|
- stat .
|
|
- ls -flh
|
|
- make -B test
|
|
|
|
# attempt to migrate
|
|
- cd ../..
|
|
- fusermount -u mount
|
|
|
|
- v2/lfs --migrate /dev/loop0
|
|
- v2/lfs /dev/loop0 mount
|
|
|
|
# run self-host test with v2 right where we left off
|
|
- ls mount
|
|
- cd mount/littlefs
|
|
- stat .
|
|
- ls -flh
|
|
- make -B test
|
|
|
|
# automatically create releases
|
|
- stage: deploy
|
|
env:
|
|
- NAME=deploy
|
|
script:
|
|
- |
|
|
bash << 'SCRIPT'
|
|
set -ev
|
|
# Find version defined in lfs.h
|
|
LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
|
|
LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
|
|
LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
|
|
# Grab latests patch from repo tags, default to 0, needs finagling
|
|
# to get past github's pagination api
|
|
PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.
|
|
PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I \
|
|
| sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' \
|
|
|| echo $PREV_URL)
|
|
LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \
|
|
| jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g")
|
|
.captures[].string | tonumber) | max + 1' \
|
|
|| echo 0)
|
|
# We have our new version
|
|
LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
|
|
echo "VERSION $LFS_VERSION"
|
|
# Check that we're the most recent commit
|
|
CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \
|
|
https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \
|
|
| jq -re '.sha')
|
|
[ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0
|
|
# Create major branch
|
|
git branch v$LFS_VERSION_MAJOR HEAD
|
|
# Create major prefix branch
|
|
git config user.name "geky bot"
|
|
git config user.email "bot@geky.net"
|
|
git fetch https://github.com/$TRAVIS_REPO_SLUG.git \
|
|
--depth=50 v$LFS_VERSION_MAJOR-prefix || true
|
|
./scripts/prefix.py lfs$LFS_VERSION_MAJOR
|
|
git branch v$LFS_VERSION_MAJOR-prefix $( \
|
|
git commit-tree $(git write-tree) \
|
|
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
|
|
-p HEAD \
|
|
-m "Generated v$LFS_VERSION_MAJOR prefixes")
|
|
git reset --hard
|
|
# Update major version branches (vN and vN-prefix)
|
|
git push --atomic https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \
|
|
v$LFS_VERSION_MAJOR \
|
|
v$LFS_VERSION_MAJOR-prefix
|
|
# Build release notes
|
|
PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
|
|
if [ ! -z "$PREV" ]
|
|
then
|
|
echo "PREV $PREV"
|
|
CHANGES=$(git log --oneline $PREV.. --grep='^Merge' --invert-grep)
|
|
printf "CHANGES\n%s\n\n" "$CHANGES"
|
|
fi
|
|
case ${GEKY_BOT_DRAFT:-minor} in
|
|
true) DRAFT=true ;;
|
|
minor) DRAFT=$(jq -R 'endswith(".0")' <<< "$LFS_VERSION") ;;
|
|
false) DRAFT=false ;;
|
|
esac
|
|
# Create the release and patch version tag (vN.N.N)
|
|
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
|
|
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
|
|
-d "{
|
|
\"tag_name\": \"$LFS_VERSION\",
|
|
\"name\": \"${LFS_VERSION%.0}\",
|
|
\"target_commitish\": \"$TRAVIS_COMMIT\",
|
|
\"draft\": $DRAFT,
|
|
\"body\": $(jq -sR '.' <<< "$CHANGES")
|
|
}" #"
|
|
SCRIPT
|
|
|
|
# manage statuses
|
|
before_install:
|
|
- |
|
|
# don't clobber other (not us) failures
|
|
if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
|
|
| jq -e ".statuses[] | select(
|
|
.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
|
|
.state == \"failure\" and
|
|
(.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
|
|
then
|
|
curl -u "$GEKY_BOT_STATUSES" -X POST \
|
|
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
|
|
-d "{
|
|
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
|
|
\"state\": \"pending\",
|
|
\"description\": \"${STATUS:-In progress}\",
|
|
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
|
|
}"
|
|
fi
|
|
|
|
after_failure:
|
|
- |
|
|
# don't clobber other (not us) failures
|
|
if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
|
|
| jq -e ".statuses[] | select(
|
|
.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
|
|
.state == \"failure\" and
|
|
(.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
|
|
then
|
|
curl -u "$GEKY_BOT_STATUSES" -X POST \
|
|
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
|
|
-d "{
|
|
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
|
|
\"state\": \"failure\",
|
|
\"description\": \"${STATUS:-Failed}\",
|
|
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
|
|
}"
|
|
fi
|
|
|
|
after_success:
|
|
- |
|
|
# don't clobber other (not us) failures
|
|
# only update if we were last job to mark in progress,
|
|
# this isn't perfect but is probably good enough
|
|
if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
|
|
| jq -e ".statuses[] | select(
|
|
.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
|
|
(.state == \"failure\" or .state == \"pending\") and
|
|
(.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
|
|
then
|
|
curl -u "$GEKY_BOT_STATUSES" -X POST \
|
|
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
|
|
-d "{
|
|
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
|
|
\"state\": \"success\",
|
|
\"description\": \"${STATUS:-Passed}\",
|
|
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
|
|
}"
|
|
fi
|