Skip to content

Commit 4658ed8

Browse files
committed
Using gnu-tar on macOS.
1 parent 7d24514 commit 4658ed8

File tree

3 files changed

+55
-49
lines changed

3 files changed

+55
-49
lines changed

.github/workflows/ArtifactsUpload.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -470,13 +470,8 @@ jobs:
470470
matrix:
471471
os:
472472
- {icon: '🐧', name: 'Ubuntu', image: 'ubuntu-24.04'}
473+
- {icon: '🍏', name: 'macOS', image: 'macos-14' }
473474
- {icon: '🪟', name: 'Windows', image: 'windows-2022'}
474-
option:
475-
- {can-fail: false}
476-
include:
477-
- {os: {icon: '🍏', name: 'macOS', image: 'macos-14'}, option: {can-fail: true}}
478-
479-
continue-on-error: ${{ matrix.option.can-fail }}
480475

481476
defaults:
482477
run:

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,27 @@ jobs:
9898

9999
## Limitations of `tar`
100100

101-
This action uses `tar` as provided by the GitHub runner's operating system images.
101+
This composite action uses `tar`/`gtar` (GNU tar) as provided by the GitHub runner's operating system images.
102102

103-
### On Linux and Windows (GNU tar)
103+
### On Linux, macOS and Windows (GNU tar)
104104

105105
To ensure files starting with a dash aren't considered command line options to `tar`, `tar` is called with
106106
`--verbatim-files-from` option.
107107

108108
To ensure files are extracted and assigned to the owner/group of the extracting user, options `--owner=root:0` and
109109
`--group=root:0` are used when creating the tarball.
110110

111+
In case, parameter `include-hidden-files` isn't set, hidden files (dot-files) are removed from the tarball in a further
112+
cleanup step using the `--delete` command. This step is needed to ensure compatibility with the original
113+
`actions/upload-artifact` action provided by GitHub.
111114

112-
### On macOS (BSD tar)
115+
### Alternative BSD tar on macOS
113116

117+
BSD tar has even worse limitations than GNU tar and offers fewer features. Thus, this composite action uses GNU tar on
118+
macOS, too. Fortunately, GNU tar (`gtar`) is already preinstalled via homebrew on all macOS runner images provided by
119+
GitHub. For more details on BSD tar expand the following collapsible section.
120+
121+
<details><summary>Unused BSD tar on macOS </summary>
114122
⚠ BSD tar doesn't support a `--delete` option. Thus, hidden files (dot files) can't be removed (excluded) from tarballs.
115123
Removing discovered hidden files afterward from created tarballs is used on runner OS providing GNU tar. This technique
116124
can't be applied to BSD tar. [^2]
@@ -129,7 +137,7 @@ as a command line option.
129137

130138
To ensure files are extracted and assigned to the owner/group of the extracting user, options `--gname=root`, `--gid=0`,
131139
`--uname=root` and `--uid=0` are used when creating the tarball.
132-
140+
</details>
133141

134142
## Dependencies
135143

action.yml

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,23 @@ runs:
131131
ANSI_LIGHT_BLUE="\e[94m"
132132
ANSI_NOCOLOR=$'\x1b[0m'
133133
134+
if ! [[ "${{ runner.os }}" == "macOS" || "${{ runner.os }}" == "Linux" || "${{ runner.os }}" == "Windows" ]]; then
135+
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "Unsupported runner OS '${{ runner.os }}'."
136+
exit 1
137+
fi
138+
134139
if [[ "${{ inputs.investigate }}" == "true" ]]; then
135-
printf "::group::${ANSI_LIGHT_BLUE}List all shell options via 'shopt' ...${ANSI_NOCOLOR}\n"
140+
printf "::group::${ANSI_LIGHT_BLUE}%s${ANSI_NOCOLOR}\n" "List all shell options via 'shopt' ..."
136141
shopt
137142
printf "::endgroup::\n"
138143
fi
139144
145+
if [[ "${{ runner.os }}" == "macOS" ]]; then
146+
tarProg="gtar"
147+
else
148+
tarProg="tar"
149+
fi
150+
140151
if [[ "${{ inputs.working-directory }}" != "" ]]; then
141152
printf "%s" "Changing artifact root directory to '${{ inputs.working-directory }}' ... "
142153
if [[ -d "${{ inputs.working-directory }}" ]]; then
@@ -190,48 +201,32 @@ runs:
190201
done | sort | uniq
191202
}
192203
193-
printf "::group::${ANSI_LIGHT_BLUE}List all pattern for 'tar' ...${ANSI_NOCOLOR}\n"
204+
printf "::group::${ANSI_LIGHT_BLUE}List all pattern for '${tarProg}' ...${ANSI_NOCOLOR}\n"
194205
while IFS=$'\r\n' read -r pattern; do
195206
printf " %s\n" "${pattern}"
196207
done <<<$(print_files_unique "${PATTERNS[@]}")
197208
printf "::endgroup::\n"
198209
199-
printf "%s\n" "Checking tar ($(which tar)): ${ANSI_CYAN}$(tar --version | head -n 1)${ANSI_NOCOLOR}"
200-
printf "%s" "Assemble OS specific tar command line options ... "
201-
if [[ "${{ runner.os }}" == "macOS" ]]; then
202-
printf "%s\n" "${ANSI_LIGHT_YELLOW}[macOS]${ANSI_NOCOLOR}"
203-
204-
# Options for BSD tar
205-
tarOptions=("--gname=root" "--gid=0" "--uname=root" "--uid=0")
206-
207-
# Option to read filenames from file
208-
filesFrom=("-T")
209-
elif [[ "${{ runner.os }}" == "Linux" || "${{ runner.os }}" == "Windows" ]]; then
210-
printf "%s\n" "${ANSI_LIGHT_GREEN}[${{ runner.os }}]${ANSI_NOCOLOR}"
211-
212-
# Options for GNU tar
213-
tarOptions=("--owner=root:0" "--group=root:0")
210+
printf "%s\n" "Checking ${tarProg} ($(which ${tarProg})): ${ANSI_CYAN}$(${tarProg} --version | head -n 1)${ANSI_NOCOLOR}"
211+
printf "%s\n" "Assemble OS specific tar command line options ... ${ANSI_LIGHT_GREEN}[${{ runner.os }}]${ANSI_NOCOLOR}"
214212
215-
# Option to read filenames from file
216-
filesFrom=("--verbatim-files-from" "--files-from")
217-
else
218-
printf "%s\n" "${ANSI_LIGHT_RED}[UNSUPPORTED]${ANSI_NOCOLOR}"
219-
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "Unsupported runner OS '${{ runner.os }}'."
220-
exit 1
221-
fi
213+
# Options for GNU tar
214+
tarOptions=("--owner=root:0" "--group=root:0")
215+
# Option to read filenames from file
216+
filesFrom=("--verbatim-files-from" "--files-from")
222217
223218
printf "%s" "Creating temporary tarball '${tarDirectory}${{ inputs.tarball-name }}' ... "
224-
msg=$(tar -cf "${tarDirectory}${{ inputs.tarball-name }}" "${tarOptions[@]}" "${filesFrom[@]}" <(print_files_unique "${PATTERNS[@]}"))
219+
msg=$(${tarProg} -cf "${tarDirectory}${{ inputs.tarball-name }}" "${tarOptions[@]}" "${filesFrom[@]}" <(print_files_unique "${PATTERNS[@]}"))
225220
if [[ $? -ne 0 ]]; then
226221
printf "%s\n" "${ANSI_LIGHT_RED}[FAILED]${ANSI_NOCOLOR}"
227-
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "tar: ${msg}"
222+
printf "::error title=%s::%s\n" "pyTooling/upload-artifact" "${tarProg}: ${msg}"
228223
exit 1
229224
else
230225
printf "%s\n" "${ANSI_LIGHT_GREEN}[OK]${ANSI_NOCOLOR}"
231226
fi
232227
233-
dirCount=$(tar -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -E '/$' | wc -l)
234-
fileCount=$(tar -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -v -E '/$' | wc -l)
228+
dirCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -E '/$' | wc -l)
229+
fileCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -v -E '/$' | wc -l)
235230
printf "%s\n" "${ANSI_CYAN}Collected items:${ANSI_NOCOLOR}"
236231
printf " %s\n" "${ANSI_CYAN}Directories: ${dirCount}${ANSI_NOCOLOR}"
237232
printf " %s\n" "${ANSI_CYAN}Files: ${fileCount}${ANSI_NOCOLOR}"
@@ -264,17 +259,19 @@ runs:
264259
ANSI_LIGHT_BLUE="\e[94m"
265260
ANSI_NOCOLOR=$'\x1b[0m'
266261
267-
if [[ "${{ runner.os }}" != "macOS" ]]; then
268-
printf "::group::${ANSI_LIGHT_BLUE}Removing unwanted files from '${{ inputs.tarball-name }}' ...:${ANSI_NOCOLOR}\n"
269-
while IFS=$'\r\n' read -r file; do
270-
printf " %s\n" "${file}"
271-
tar -vf "${{ inputs.tarball-name }}" --delete "${file}"
272-
done <<<$(tar -tf "${{ inputs.tarball-name }}" | grep -E '^\.|/\.')
273-
printf "::endgroup::\n"
262+
if [[ "${{ runner.os }}" == "macOS" ]]; then
263+
tarProg="gtar"
274264
else
275-
printf "::warning title=%s::%s\n" "pyTooling/upload-artifact" "macOS doesn't support removing hidden files."
265+
tarProg="tar"
276266
fi
277267
268+
printf "::group::${ANSI_LIGHT_BLUE}Removing unwanted files from '${{ inputs.tarball-name }}' ...:${ANSI_NOCOLOR}\n"
269+
while IFS=$'\r\n' read -r file; do
270+
printf " %s\n" "${file}"
271+
${tarProg} -vf "${{ inputs.tarball-name }}" --delete "${file}"
272+
done <<<$(${tarProg} -tf "${{ inputs.tarball-name }}" | grep -E '^\.|/\.')
273+
printf "::endgroup::\n"
274+
278275
- name: List content of the generated tarball
279276
id: investigate
280277
if: inputs.mode == 'tar' && inputs.investigate == 'true'
@@ -290,11 +287,17 @@ runs:
290287
ANSI_LIGHT_BLUE="\e[94m"
291288
ANSI_NOCOLOR=$'\x1b[0m'
292289
290+
if [[ "${{ runner.os }}" == "macOS" ]]; then
291+
tarProg="gtar"
292+
else
293+
tarProg="tar"
294+
fi
295+
293296
printf "::group::${ANSI_LIGHT_BLUE}Content of '${{ inputs.tarball-name }}':${ANSI_NOCOLOR}\n"
294-
tar -tvf "${{ inputs.tarball-name }}"
297+
${tarProg} -tvf "${{ inputs.tarball-name }}"
295298
printf "\n"
296-
dirCount=$(tar -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -E '/$' | wc -l)
297-
fileCount=$(tar -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -v -E '/$' | wc -l)
299+
dirCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -E '/$' | wc -l)
300+
fileCount=$(${tarProg} -tf "${tarDirectory}${{ inputs.tarball-name }}" | grep -v -E '/$' | wc -l)
298301
printf "%s\n" "${ANSI_CYAN}Directories: ${dirCount} Files: ${fileCount}${ANSI_NOCOLOR}"
299302
printf "::endgroup::\n"
300303

0 commit comments

Comments
 (0)