Skip to content

Commit 6531f50

Browse files
Add support for nested ignore files (#117)
**Please check if the PR fulfills these requirements** - [x] The commit message follows our [guidelines](https://github.com/get-woke/woke/blob/main/CONTRIBUTING.md) - [x] Tests for the changes have been added (for bug fixes / features) - [x] Docs have been added / updated (for bug fixes / features) **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) Feature **What is the current behavior?** (You can also link to an open issue here) Woke currently only looks at .gitignore and .wokeignore files in the current directory. **What is the new behavior (if this is a feature change)?** Woke will now traverse a repo and build a priority ranked list of ignore rules in exactly the same way that git does for .gitignore files at different directory levels. The tool will look for the root git directory (where the .git folder is) and use that for the root. If no root git directory is found then woke will just run with the current directory as root (still traversing children folders). **Does this PR introduce a breaking change?** (What changes might users need to make due to this PR?) No **Other information**: Addresses #98
1 parent 1b32c2b commit 6531f50

File tree

19 files changed

+554
-132
lines changed

19 files changed

+554
-132
lines changed

.devcontainer/devcontainer.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@
3737
"go.lintFlags": [
3838
"--fast"
3939
],
40+
"go.coverOnSave": true,
41+
"go.coverageDecorator": {
42+
"type": "gutter",
43+
"coveredHighlightColor": "rgba(64,128,128,0.5)",
44+
"uncoveredHighlightColor": "rgba(128,64,64,0.25)",
45+
"coveredGutterStyle": "blockgreen",
46+
"uncoveredGutterStyle": "blockred"
47+
},
48+
"go.coverOnSingleTest": true,
4049
"editor.formatOnSave": true,
4150
"files.insertFinalNewline": true,
4251
"files.trimFinalNewlines": true,

.devcontainer/scripts/docker-debian.sh

Lines changed: 133 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md
88
# Maintainer: The VS Code and Codespaces Teams
99
#
10-
# Syntax: ./docker-debian.sh [enable non-root docker socket access flag] [source socket] [target socket] [non-root user] [use moby]
10+
# Syntax: ./docker-debian.sh [enable non-root docker socket access flag] [source socket] [target socket] [non-root user] [use moby] [CLI version]
11+
# shellcheck disable=SC2068,SC2086,SC2155,SC2012,SC2236,SC1091
1112

1213
ENABLE_NONROOT_DOCKER=${1:-"true"}
1314
SOURCE_SOCKET=${2:-"/var/run/docker-host.sock"}
1415
TARGET_SOCKET=${3:-"/var/run/docker.sock"}
1516
USERNAME=${4:-"automatic"}
1617
USE_MOBY=${5:-"true"}
18+
DOCKER_VERSION=${6:-"latest"}
19+
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
20+
DOCKER_DASH_COMPOSE_VERSION="1"
1721

1822
set -e
1923

@@ -39,8 +43,23 @@ elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
3943
USERNAME=root
4044
fi
4145

46+
# Get central common setting
47+
get_common_setting() {
48+
if [ "${common_settings_file_loaded}" != "true" ]; then
49+
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
50+
common_settings_file_loaded=true
51+
fi
52+
if [ -f "/tmp/vsdc-settings.env" ]; then
53+
local multi_line=""
54+
if [ "$2" = "true" ]; then multi_line="-z"; fi
55+
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
56+
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
57+
fi
58+
echo "$1=${!1}"
59+
}
60+
4261
# Function to run apt-get if needed
43-
apt-get-update-if-needed()
62+
apt_get_update_if_needed()
4463
{
4564
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
4665
echo "Running apt-get update..."
@@ -50,33 +69,114 @@ apt-get-update-if-needed()
5069
fi
5170
}
5271

72+
# Checks if packages are installed and installs them if not
73+
check_packages() {
74+
if ! dpkg -s "$@" > /dev/null 2>&1; then
75+
apt_get_update_if_needed
76+
apt-get -y install --no-install-recommends "$@"
77+
fi
78+
}
79+
80+
# Figure out correct version of a three part version number is not passed
81+
find_version_from_git_tags() {
82+
local variable_name=$1
83+
local requested_version=${!variable_name}
84+
if [ "${requested_version}" = "none" ]; then return; fi
85+
local repository=$2
86+
local prefix=${3:-"tags/v"}
87+
local separator=${4:-"."}
88+
local last_part_optional=${5:-"false"}
89+
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
90+
local escaped_separator=${separator//./\\.}
91+
local last_part
92+
if [ "${last_part_optional}" = "true" ]; then
93+
last_part="(${escaped_separator}[0-9]+)?"
94+
else
95+
last_part="${escaped_separator}[0-9]+"
96+
fi
97+
local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
98+
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
99+
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
100+
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
101+
else
102+
set +e
103+
declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
104+
set -e
105+
fi
106+
fi
107+
if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then
108+
echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
109+
exit 1
110+
fi
111+
echo "${variable_name}=${!variable_name}"
112+
}
113+
53114
# Ensure apt is in non-interactive to avoid prompts
54115
export DEBIAN_FRONTEND=noninteractive
55116

56-
# Install apt-transport-https, curl, gpg if missing
57-
if ! dpkg -s apt-transport-https curl ca-certificates > /dev/null 2>&1 || ! type gpg > /dev/null 2>&1; then
58-
apt-get-update-if-needed
59-
apt-get -y install --no-install-recommends apt-transport-https curl ca-certificates gnupg2
117+
# Install dependencies
118+
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
119+
if ! type git > /dev/null 2>&1; then
120+
apt_get_update_if_needed
121+
apt-get -y install git
122+
fi
123+
124+
# Source /etc/os-release to get OS info
125+
. /etc/os-release
126+
# Fetch host/container arch.
127+
architecture="$(dpkg --print-architecture)"
128+
129+
# Set up the necessary apt repos (either Microsoft's or Docker's)
130+
if [ "${USE_MOBY}" = "true" ]; then
131+
132+
cli_package_name="moby-cli"
133+
134+
# Import key safely and import Microsoft apt repo
135+
get_common_setting MICROSOFT_GPG_KEYS_URI
136+
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
137+
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
138+
else
139+
# Name of proprietary engine package
140+
cli_package_name="docker-ce-cli"
141+
142+
# Import key safely and import Docker apt repo
143+
curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg
144+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
145+
fi
146+
147+
# Refresh apt lists
148+
apt-get update
149+
150+
# Soft version matching for CLI
151+
if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then
152+
# Empty, meaning grab whatever "latest" is in apt repo
153+
cli_version_suffix=""
154+
else
155+
# Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...)
156+
docker_version_dot_escaped="${DOCKER_VERSION//./\\.}"
157+
docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}"
158+
# Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/
159+
docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)"
160+
set +e # Don't exit if finding version fails - will handle gracefully
161+
cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")"
162+
set -e
163+
if [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ]; then
164+
echo "(!) No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:"
165+
apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+'
166+
exit 1
167+
fi
168+
echo "cli_version_suffix ${cli_version_suffix}"
60169
fi
61170

62171
# Install Docker / Moby CLI if not already installed
63172
if type docker > /dev/null 2>&1; then
64173
echo "Docker / Moby CLI already installed."
65174
else
66-
# Source /etc/os-release to get OS info
67-
. /etc/os-release
68175
if [ "${USE_MOBY}" = "true" ]; then
69-
# Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install
70-
curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
71-
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
72-
apt-get update
73-
apt-get -y install --no-install-recommends moby-cli moby-buildx
176+
apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx
177+
apt-get -y install --no-install-recommends moby-compose || echo "(*) Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping."
74178
else
75-
# Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install
76-
curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg
77-
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
78-
apt-get update
79-
apt-get -y install --no-install-recommends docker-ce-cli
179+
apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix}
80180
fi
81181
fi
82182

@@ -90,19 +190,26 @@ else
90190
fi
91191
if [ "${TARGET_COMPOSE_ARCH}" != "x86_64" ]; then
92192
# Use pip to get a version that runns on this architecture
93-
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv pipx > /dev/null 2>&1; then
94-
apt-get-update-if-needed
95-
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv pipx
193+
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then
194+
apt_get_update_if_needed
195+
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv
96196
fi
97197
export PIPX_HOME=/usr/local/pipx
98198
mkdir -p ${PIPX_HOME}
99199
export PIPX_BIN_DIR=/usr/local/bin
200+
export PYTHONUSERBASE=/tmp/pip-tmp
100201
export PIP_CACHE_DIR=/tmp/pip-tmp/cache
101-
pipx install --system-site-packages --pip-args '--no-cache-dir --force-reinstall' docker-compose
202+
pipx_bin=pipx
203+
if ! type pipx > /dev/null 2>&1; then
204+
pip3 install --disable-pip-version-check --no-warn-script-location --no-cache-dir --user pipx
205+
pipx_bin=/tmp/pip-tmp/bin/pipx
206+
fi
207+
${pipx_bin} install --system-site-packages --pip-args '--no-cache-dir --force-reinstall' docker-compose
102208
rm -rf /tmp/pip-tmp
103209
else
104-
LATEST_COMPOSE_VERSION=$(basename "$(curl -fsSL -o /dev/null -w "%{url_effective}" https://github.com/docker/compose/releases/latest)")
105-
curl -fsSL "https://github.com/docker/compose/releases/download/${LATEST_COMPOSE_VERSION}/docker-compose-$(uname -s)-${TARGET_COMPOSE_ARCH}" -o /usr/local/bin/docker-compose
210+
find_version_from_git_tags DOCKER_DASH_COMPOSE_VERSION "https://github.com/docker/compose" "tags/"
211+
echo "(*) Installing docker-compose ${DOCKER_DASH_COMPOSE_VERSION}..."
212+
curl -fsSL "https://github.com/docker/compose/releases/download/${DOCKER_DASH_COMPOSE_VERSION}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
106213
chmod +x /usr/local/bin/docker-compose
107214
fi
108215
fi
@@ -111,6 +218,7 @@ fi
111218
if [ -f "/usr/local/share/docker-init.sh" ]; then
112219
exit 0
113220
fi
221+
echo "docker-init doesnt exist, adding..."
114222

115223
# By default, make the source and target sockets the same
116224
if [ "${SOURCE_SOCKET}" != "${TARGET_SOCKET}" ]; then
@@ -128,7 +236,7 @@ fi
128236
# If enabling non-root access and specified user is found, setup socat and add script
129237
chown -h "${USERNAME}":root "${TARGET_SOCKET}"
130238
if ! dpkg -s socat > /dev/null 2>&1; then
131-
apt-get-update-if-needed
239+
apt_get_update_if_needed
132240
apt-get -y install socat
133241
fi
134242
tee /usr/local/share/docker-init.sh > /dev/null \

cmd/root.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,19 @@ func rootRunE(cmd *cobra.Command, args []string) error {
101101

102102
var ignorer *ignore.Ignore
103103
if !noIgnore {
104-
ignorer = ignore.NewIgnore(cfg.IgnoreFiles)
104+
cwd, err := os.Getwd()
105+
if err != nil {
106+
return err
107+
}
108+
fs, err := ignore.GetRootGitDir(cwd)
109+
if err != nil {
110+
return err
111+
}
112+
ignorer, err = ignore.NewIgnore(fs, cfg.IgnoreFiles)
113+
if err != nil {
114+
return err
115+
}
105116
}
106-
107117
p := parser.NewParser(cfg.Rules, ignorer)
108118

109119
print, err := printer.NewPrinter(outputName, output.Stdout)

cmd/root_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ func TestRunE(t *testing.T) {
111111

112112
t.Run("findings w error", func(t *testing.T) {
113113
exitOneOnFailure = true
114+
// don't ignore testdata folder
115+
noIgnore = true
116+
114117
t.Cleanup(func() {
115118
exitOneOnFailure = false
116119
})

docs/ignore.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,27 @@ func main() {
7474
fmt.Println("and here is the blacklist")
7575
}
7676
```
77+
78+
## Nested Ignore Files
79+
80+
`woke` will apply ignore rules from nested ignore files to any child files/folders, similar to a nested `.gitignore` file. Nested ignore files work for any ignore file type listed above.
81+
82+
```txt
83+
project
84+
│ README.md
85+
│ .wokeignore (applies to whole project)
86+
87+
└───folder1
88+
│ │ file011.txt
89+
│ │ file012.txt
90+
│ │ .wokeignore (applies to file011.txt, file012.txt, and subfolder1)
91+
│ │
92+
│ └───subfolder1
93+
│ │ file111.txt
94+
│ │ file112.txt
95+
│ │ ...
96+
97+
└───folder2
98+
│ file021.txt
99+
│ file022.txt
100+
```

docs/snippets/woke.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ woke [globs ...] [flags]
3131
--stdin Read from stdin
3232
```
3333

34-
###### Auto generated by spf13/cobra on 22-Nov-2021
34+
###### Auto generated by spf13/cobra on 6-Dec-2021

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ require (
66
github.com/caitlinelfring/go-env-default v1.0.0
77
github.com/fatih/color v1.13.0
88
github.com/get-woke/fastwalk v1.0.0
9-
github.com/get-woke/go-gitignore v1.1.2
9+
github.com/go-git/go-billy/v5 v5.3.1
10+
github.com/go-git/go-git/v5 v5.4.2
1011
github.com/mattn/go-colorable v0.1.12
1112
github.com/mitchellh/go-homedir v1.1.0
1213
github.com/rs/zerolog v1.26.0
@@ -17,11 +18,14 @@ require (
1718
)
1819

1920
require (
21+
github.com/acomagu/bufpipe v1.0.3 // indirect
2022
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
2123
github.com/davecgh/go-spew v1.1.1 // indirect
2224
github.com/fsnotify/fsnotify v1.5.1 // indirect
25+
github.com/go-git/gcfg v1.5.0 // indirect
2326
github.com/hashicorp/hcl v1.0.0 // indirect
2427
github.com/inconshreveable/mousetrap v1.0.0 // indirect
28+
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
2529
github.com/magiconair/properties v1.8.5 // indirect
2630
github.com/mattn/go-isatty v0.0.14 // indirect
2731
github.com/mitchellh/mapstructure v1.4.2 // indirect
@@ -34,8 +38,12 @@ require (
3438
github.com/spf13/jwalterweatherman v1.1.0 // indirect
3539
github.com/spf13/pflag v1.0.5 // indirect
3640
github.com/subosito/gotenv v1.2.0 // indirect
41+
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
3742
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
3843
golang.org/x/text v0.3.6 // indirect
3944
gopkg.in/ini.v1 v1.63.2 // indirect
45+
gopkg.in/warnings.v0 v0.1.2 // indirect
4046
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
4147
)
48+
49+
replace github.com/go-git/go-git/v5 => github.com/inclusive-dev-tools/go-git/v5 v5.4.4

0 commit comments

Comments
 (0)