Fix bugs, improve robustness, and add local dashboard-icons support
- mirror-sync.sh: fix upstream_check/time_file_check to handle missing
timestamp file and empty Last-Modified header; fix rebuild_dusum_totals
variable shadowing; propagate return codes from install helpers; refactor
git_sync out of subshell; scope LOGFILE_STAGE2 to stage-2 block; clean up
mirror_update_file and QFM in-progress files on failure; fix total_time
initialization and wget_sync exit propagation
- mirror-file-generator.sh: add icons_local_repo/icons_repo_url/icons_repo_refresh
for offline icon serving; move PIDFILE to /tmp; enhance image_copy to
refresh stale cached files; fix temp index file cleanup on empty output;
safer ${var:?} → [[ -n $var ]] guards throughout
- README.md: fix typos, heading levels, variable names, and document new
icon repo config options
- Bump VERSION to 20260602 in both scripts
This commit is contained in:
parent
921ba5a73b
commit
81be7ddd2e
3 changed files with 201 additions and 126 deletions
61
README.md
61
README.md
|
|
@ -1,5 +1,5 @@
|
||||||
# mirror-sync
|
# mirror-sync
|
||||||
A tool to mirror repostories for Linux and other similar tools. This tool is designed to help follow upstream mirror instructions, and implement the features they expect from a downstream official mirror. It also includes features to help keep you in the loop in case of situations that need manual intervention.
|
A tool to mirror repositories for Linux and other similar tools. This tool is designed to help follow upstream mirror instructions, and implement the features they expect from a downstream official mirror. It also includes features to help keep you in the loop in case of situations that need manual intervention.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
It is suggested that you mirror using a sub user account, this tool prevents execution as root to protect you. Once you have an user account dedicated to mirror activities, you can make the log directory, configure logrotate, and add a configuration file to define configurations.
|
It is suggested that you mirror using a sub user account, this tool prevents execution as root to protect you. Once you have an user account dedicated to mirror activities, you can make the log directory, configure logrotate, and add a configuration file to define configurations.
|
||||||
|
|
@ -29,7 +29,7 @@ The configuration file is in `/etc/mirror-sync.conf` and is formatted in bash.
|
||||||
|
|
||||||
## Main configurations
|
## Main configurations
|
||||||
### MODULES
|
### MODULES
|
||||||
The available modules separated by space. Each module is a separate repostory to sync, and this list allows the script to know how to find their configs.
|
The available modules separated by space. Each module is a separate repository to sync, and this list allows the script to know how to find their configs.
|
||||||
|
|
||||||
### TRACEHOST
|
### TRACEHOST
|
||||||
The hostname to show in trace project files, it defaults to the FQDN hostname of the server.
|
The hostname to show in trace project files, it defaults to the FQDN hostname of the server.
|
||||||
|
|
@ -47,7 +47,7 @@ If you wish to override where logs are stored, the default is `/var/log/mirror-s
|
||||||
Timeout before a sync is cancelled, defaults to `timeout 1d` which should work for most mirrors.
|
Timeout before a sync is cancelled, defaults to `timeout 1d` which should work for most mirrors.
|
||||||
|
|
||||||
### max_errors
|
### max_errors
|
||||||
How many errors before an email is sent regarding the issue. This allows you to ignore anomolies.
|
How many errors before an email is sent regarding the issue. This allows you to ignore anomalies.
|
||||||
|
|
||||||
### upstream_max_age
|
### upstream_max_age
|
||||||
If the upstream last modified date is older than the defined number of seconds, the upstream check will skip syncing. Default is 5 hours.
|
If the upstream last modified date is older than the defined number of seconds, the upstream check will skip syncing. Default is 5 hours.
|
||||||
|
|
@ -98,7 +98,7 @@ How did the sync occur, cron job or manually via ssh? This is auto detected and
|
||||||
Path to save a grand total of each disk usage sum in human readable form.
|
Path to save a grand total of each disk usage sum in human readable form.
|
||||||
|
|
||||||
### dusum_kbytes_total_file
|
### dusum_kbytes_total_file
|
||||||
Path to save a grand total of each disk usage sum in killo bytes.
|
Path to save a grand total of each disk usage sum in kilobytes.
|
||||||
|
|
||||||
## Module specific configurations
|
## Module specific configurations
|
||||||
Each module is configured via configurations prefixed by the module name. The one configuration used by all modules is the `_sync_method` configuration which defines what sync method to use. Each sync method has different configurations available. The default sync method is rsync.
|
Each module is configured via configurations prefixed by the module name. The one configuration used by all modules is the `_sync_method` configuration which defines what sync method to use. Each sync method has different configurations available. The default sync method is rsync.
|
||||||
|
|
@ -114,7 +114,7 @@ Each repo has at bare minimum the following configurations:
|
||||||
Synchronizes a git repository via git pull. To use this method, you need to have the git package installed.
|
Synchronizes a git repository via git pull. To use this method, you need to have the git package installed.
|
||||||
|
|
||||||
#### options
|
#### options
|
||||||
Extra options appended to `get pull`.
|
Extra options appended to `git pull`.
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -132,7 +132,7 @@ The bucket URL to sync with.
|
||||||
#### aws_access_key
|
#### aws_access_key
|
||||||
The access key for the s3 bucket.
|
The access key for the s3 bucket.
|
||||||
|
|
||||||
### aws_secret_key
|
#### aws_secret_key
|
||||||
The secret for the s3 bucket.
|
The secret for the s3 bucket.
|
||||||
|
|
||||||
#### aws_endpoint_url
|
#### aws_endpoint_url
|
||||||
|
|
@ -160,14 +160,14 @@ The bucket URL to sync with.
|
||||||
#### aws_access_key
|
#### aws_access_key
|
||||||
The access key for the s3 bucket.
|
The access key for the s3 bucket.
|
||||||
|
|
||||||
### aws_secret_key
|
#### aws_secret_key
|
||||||
The secret for the s3 bucket.
|
The secret for the s3 bucket.
|
||||||
|
|
||||||
#### aws_endpoint_url
|
#### aws_endpoint_url
|
||||||
If you are using a third party S3 compatible service, you can enter their endpoint URL here in format of HOSTNAME:PORT.
|
If you are using a third party S3 compatible service, you can enter their endpoint URL here in format of HOSTNAME:PORT.
|
||||||
|
|
||||||
#### options
|
#### options
|
||||||
Extra options to append to `s5cmd`.
|
Extra options to append to `s3cmd`.
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -199,7 +199,7 @@ The bucket URL to sync with. You must end the bucket url with `*` for s5cmd to w
|
||||||
#### aws_access_key
|
#### aws_access_key
|
||||||
The access key for the s3 bucket.
|
The access key for the s3 bucket.
|
||||||
|
|
||||||
### aws_secret_key
|
#### aws_secret_key
|
||||||
The secret for the s3 bucket.
|
The secret for the s3 bucket.
|
||||||
|
|
||||||
#### aws_endpoint_url
|
#### aws_endpoint_url
|
||||||
|
|
@ -275,9 +275,9 @@ If your repo needs a 2 stage rsync, define some options here. The most basic opt
|
||||||
A hook to run prior to the second stage sync.
|
A hook to run prior to the second stage sync.
|
||||||
|
|
||||||
#### upstream_check
|
#### upstream_check
|
||||||
An http URL to check the last modified date as a reference for if the upstream mirror was possibly modified recently. This option is mainly here to lower the impact on upstream mirrors so that mirrorning happens less often. See `upstream_timestamp_min` and `upstream_max_age` for global configuration options of this check.
|
An http URL to check the last modified date as a reference for if the upstream mirror was possibly modified recently. This option is mainly here to lower the impact on upstream mirrors so that mirroring happens less often. See `upstream_timestamp_min` and `upstream_max_age` for global configuration options of this check.
|
||||||
|
|
||||||
### time_file_check
|
#### time_file_check
|
||||||
Name of a time file to check if the upstream has updated before syncing all files to reduce load on upstream mirrors.
|
Name of a time file to check if the upstream has updated before syncing all files to reduce load on upstream mirrors.
|
||||||
|
|
||||||
#### report_mirror
|
#### report_mirror
|
||||||
|
|
@ -334,7 +334,7 @@ example_type="iso"
|
||||||
### qfm
|
### qfm
|
||||||
Quick Fedora Mirror is a tool to help Fedora mirrors distribute changes faster and save on resources when trying to discover what needs to be synced. To use this method, you must have both the rsync and zsh package installed. This tool automatically downloads QFM if you do not already have it installed.
|
Quick Fedora Mirror is a tool to help Fedora mirrors distribute changes faster and save on resources when trying to discover what needs to be synced. To use this method, you must have both the rsync and zsh package installed. This tool automatically downloads QFM if you do not already have it installed.
|
||||||
|
|
||||||
This tool requires that the upstream mirror has an module with sub modules designed for use with quick-fedora-mirror. You can use this tool with non-fedora mirrors, however they must follow the fedora module configurations. For fedora mirrors, you can utilize [tier 1 mirrors](https://fedoraproject.org/wiki/Infrastructure/Mirroring/Tiering#Tier_1_mirrors).
|
This tool requires that the upstream mirror has a module with sub modules designed for use with quick-fedora-mirror. You can use this tool with non-fedora mirrors, however they must follow the fedora module configurations. For fedora mirrors, you can utilize [tier 1 mirrors](https://fedoraproject.org/wiki/Infrastructure/Mirroring/Tiering#Tier_1_mirrors).
|
||||||
|
|
||||||
You can list modules available on an rsync server with:
|
You can list modules available on an rsync server with:
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -405,7 +405,7 @@ example_type=rpm
|
||||||
## CLI Options
|
## CLI Options
|
||||||
There are not that many cli options available, usage is as follows:
|
There are not that many cli options available, usage is as follows:
|
||||||
```
|
```
|
||||||
[--help|--update-support-utilities] {module} [--force]
|
[--help|--update-support-utilities|--version] {module} [--force]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Requirements list
|
## Requirements list
|
||||||
|
|
@ -449,7 +449,7 @@ This tool utilizes the same config file as mirror-sync, and shares the following
|
||||||
* timestamp - Used for sync time.
|
* timestamp - Used for sync time.
|
||||||
* dusum - Used for disk usage summary.
|
* dusum - Used for disk usage summary.
|
||||||
|
|
||||||
The tool also adds the following repo
|
The tool also adds the following repo-specific configurations:
|
||||||
|
|
||||||
### section
|
### section
|
||||||
What section to associate the repo with.
|
What section to associate the repo with.
|
||||||
|
|
@ -460,7 +460,7 @@ A title for the repo to show instead of the directory name.
|
||||||
### repo_icon
|
### repo_icon
|
||||||
The repo icon, will default to tux if not defined. The icon can be defined as an http(s) link, file path, a file stored in the template directory, or png image name from [Dashboard Icons](https://github.com/walkxcode/dashboard-icons/tree/main/png). The script will automatically make a copy or download the icon to the image folder.
|
The repo icon, will default to tux if not defined. The icon can be defined as an http(s) link, file path, a file stored in the template directory, or png image name from [Dashboard Icons](https://github.com/walkxcode/dashboard-icons/tree/main/png). The script will automatically make a copy or download the icon to the image folder.
|
||||||
|
|
||||||
### repo_descriotion
|
### repo_description
|
||||||
A description to show at the bottom of the repo card.
|
A description to show at the bottom of the repo card.
|
||||||
|
|
||||||
### repo_skip
|
### repo_skip
|
||||||
|
|
@ -476,6 +476,8 @@ If you do not have a timestamp file with the UNIX timestamp of the last sync, bu
|
||||||
If you have a repo that is not synced via the mirror-sync, but want to customize its look on the generated index.html. You can define a list of custom modules with the `CUSTOM_MODULES` variable, then define any of the following configurations.
|
If you have a repo that is not synced via the mirror-sync, but want to customize its look on the generated index.html. You can define a list of custom modules with the `CUSTOM_MODULES` variable, then define any of the following configurations.
|
||||||
|
|
||||||
* repo
|
* repo
|
||||||
|
* timestamp
|
||||||
|
* dusum
|
||||||
* section
|
* section
|
||||||
* repo_title
|
* repo_title
|
||||||
* repo_icon
|
* repo_icon
|
||||||
|
|
@ -494,7 +496,7 @@ example_repo='/home/mirror/http/'
|
||||||
example_section="official"
|
example_section="official"
|
||||||
example_repo_title="Test repo"
|
example_repo_title="Test repo"
|
||||||
example_repo_icon="terminal.png"
|
example_repo_icon="terminal.png"
|
||||||
example_repo_descriont="Test, this is a test."
|
example_repo_description="Test, this is a test."
|
||||||
|
|
||||||
example2_repo='/home/mirror/windows/'
|
example2_repo='/home/mirror/windows/'
|
||||||
example2_repo_icon="windows.png"
|
example2_repo_icon="windows.png"
|
||||||
|
|
@ -526,7 +528,7 @@ A name for the global footer generation.
|
||||||
MIRRORS="mirror_example"
|
MIRRORS="mirror_example"
|
||||||
|
|
||||||
mirror_example_path="/home/mirror/mirror_docroot"
|
mirror_example_path="/home/mirror/mirror_docroot"
|
||||||
mirror_example_name="My company"
|
mirror_example_title="My company"
|
||||||
mirror_example_logo="http://example.com/logo.png"
|
mirror_example_logo="http://example.com/logo.png"
|
||||||
mirror_example_description="A public mirror provided by this cool company."
|
mirror_example_description="A public mirror provided by this cool company."
|
||||||
mirror_example_provider_site="http://www.example.com/"
|
mirror_example_provider_site="http://www.example.com/"
|
||||||
|
|
@ -537,11 +539,11 @@ mirror_example_provider_name="Company"
|
||||||
You can define multiple sections for the index.html with `SECTIONS` variable, it defaults to `official unofficial`. You can then set a default section with `section_default`, which defaults to `unofficial`. A title is auto generated as `{SECTION} Mirrors`, which you can customize with a variable named `section_{SECTION}_title`.
|
You can define multiple sections for the index.html with `SECTIONS` variable, it defaults to `official unofficial`. You can then set a default section with `section_default`, which defaults to `unofficial`. A title is auto generated as `{SECTION} Mirrors`, which you can customize with a variable named `section_{SECTION}_title`.
|
||||||
|
|
||||||
## Templates
|
## Templates
|
||||||
Where templates are stored is configured by `template_dir` which defaults to `/usr/local/share/file-generator-templates`. Default files should be stored under the `default` sub directory, and any customizations to individual mirrors should be saved under a sub directory with that mirror's name. You can add icons/logos into these template directories as well.
|
Where templates are stored is configured by `template_dir` which defaults to `/usr/local/share/mirror-file-generator/templates`. Default files should be stored under the `default` sub directory, and any customizations to individual mirrors should be saved under a sub directory with that mirror's name. You can add icons/logos into these template directories as well.
|
||||||
|
|
||||||
Default templates:
|
Default templates:
|
||||||
* header.html - The main index header.
|
* header.html - The main index header.
|
||||||
* secion.thml - Template for a secion.
|
* section.html - Template for a section.
|
||||||
* repo.html - The repo card template.
|
* repo.html - The repo card template.
|
||||||
* footer.html - The footer of the index.
|
* footer.html - The footer of the index.
|
||||||
* footer.txt - Template for the global footer file.
|
* footer.txt - Template for the global footer file.
|
||||||
|
|
@ -549,28 +551,28 @@ Default templates:
|
||||||
## Configurations of general defaults.
|
## Configurations of general defaults.
|
||||||
|
|
||||||
### index_generate
|
### index_generate
|
||||||
Rather or not to generate the index.html file.
|
Whether or not to generate the index.html file.
|
||||||
|
|
||||||
* 1 Enabled
|
* 1 Enabled
|
||||||
* 0 Disbaled
|
* 0 Disabled
|
||||||
|
|
||||||
### index_file_name
|
### index_file_name
|
||||||
If your index file name is different, you can adjust here.
|
If your index file name is different, you can adjust here.
|
||||||
|
|
||||||
### footer_generate
|
### footer_generate
|
||||||
Rather or not to generate a footer file that can be configured as the mirror's global footer.
|
Whether or not to generate a footer file that can be configured as the mirror's global footer.
|
||||||
|
|
||||||
* 1 Enabled
|
* 1 Enabled
|
||||||
* 0 Disbaled
|
* 0 Disabled
|
||||||
|
|
||||||
### footer_file_name
|
### footer_file_name
|
||||||
Alternative file name for the footer file.
|
Alternative file name for the footer file.
|
||||||
|
|
||||||
### dir_sizes_generate
|
### dir_sizes_generate
|
||||||
Rather or not to generate directory sizes file.
|
Whether or not to generate directory sizes file.
|
||||||
|
|
||||||
* 1 Enabled
|
* 1 Enabled
|
||||||
* 0 Disbaled
|
* 0 Disabled
|
||||||
|
|
||||||
### dir_sizes_file_name
|
### dir_sizes_file_name
|
||||||
Alternative file name for directory sizes file.
|
Alternative file name for directory sizes file.
|
||||||
|
|
@ -592,3 +594,12 @@ The default URL to pull icons from, defaults to [Dashboard Icons](https://github
|
||||||
|
|
||||||
### icons_default_img
|
### icons_default_img
|
||||||
A default file to use if icon or logo defined either isn't defined or isn't accessible.
|
A default file to use if icon or logo defined either isn't defined or isn't accessible.
|
||||||
|
|
||||||
|
### icons_local_repo
|
||||||
|
Local path to a cloned copy of the dashboard-icons git repository. When this directory exists, the script serves icons from it instead of fetching them over HTTP, which avoids per-icon network requests. Defaults to `$HOME/dashboard-icons`.
|
||||||
|
|
||||||
|
### icons_repo_url
|
||||||
|
Git URL used to clone the dashboard-icons repository into `icons_local_repo` if it does not already exist. Set to an empty string to disable automatic cloning. Defaults to `https://github.com/walkxcode/dashboard-icons.git`.
|
||||||
|
|
||||||
|
### icons_repo_refresh
|
||||||
|
How often (in seconds) the local dashboard-icons clone is pulled for updates. Defaults to `604800` (7 days).
|
||||||
|
|
@ -10,8 +10,9 @@ PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:$HOME/.local/
|
||||||
|
|
||||||
# Variables about this program.
|
# Variables about this program.
|
||||||
PROGRAM="mirror-file-generator"
|
PROGRAM="mirror-file-generator"
|
||||||
VERSION="20240219"
|
VERSION="20260602"
|
||||||
PIDFILE="/var/run/$PROGRAM.pid"
|
PIDPATH="/tmp"
|
||||||
|
PIDFILE="${PIDPATH}/${PROGRAM}.pid"
|
||||||
LOGFILE="/var/log/mirror-sync/$PROGRAM.log"
|
LOGFILE="/var/log/mirror-sync/$PROGRAM.log"
|
||||||
|
|
||||||
# Default variables
|
# Default variables
|
||||||
|
|
@ -24,9 +25,12 @@ footer_generate=1
|
||||||
footer_file_name="footer.txt"
|
footer_file_name="footer.txt"
|
||||||
dir_sizes_generate=1
|
dir_sizes_generate=1
|
||||||
dir_sizes_file_name="DIRECTORY_SIZES.TXT"
|
dir_sizes_file_name="DIRECTORY_SIZES.TXT"
|
||||||
dir_sizes_unknown_path="/home/mirror/dusum/unknown_dirs"
|
dir_sizes_unknown_path="$HOME/dusum/unknown_dirs"
|
||||||
dir_sizes_human_readable=1
|
dir_sizes_human_readable=1
|
||||||
icons_dir_name="img"
|
icons_dir_name="img"
|
||||||
|
icons_local_repo="$HOME/dashboard-icons"
|
||||||
|
icons_repo_url="https://github.com/walkxcode/dashboard-icons.git"
|
||||||
|
icons_repo_refresh=604800
|
||||||
icons_default_source="https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/png"
|
icons_default_source="https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/png"
|
||||||
icons_default_img="tux.png"
|
icons_default_img="tux.png"
|
||||||
|
|
||||||
|
|
@ -108,14 +112,28 @@ image_copy() {
|
||||||
local save_path="$path/$icons_dir_name/$file_name.$extension"
|
local save_path="$path/$icons_dir_name/$file_name.$extension"
|
||||||
local http_code
|
local http_code
|
||||||
|
|
||||||
# If the file isn't already saved, attempt to grab it.
|
# Determine if the saved file needs to be updated.
|
||||||
|
local needs_update=0
|
||||||
if [[ ! -e "$save_path" ]]; then
|
if [[ ! -e "$save_path" ]]; then
|
||||||
|
needs_update=1
|
||||||
|
elif [[ "$file" =~ ^http(s|)\:\/\/ ]]; then
|
||||||
|
# Re-download remote files if older than the refresh interval.
|
||||||
|
if (( $(date +%s) - $(stat --format='%Y' "$save_path") > icons_repo_refresh )); then
|
||||||
|
needs_update=1
|
||||||
|
fi
|
||||||
|
elif [[ -f $file ]]; then
|
||||||
|
# Re-copy local files if the source mtime differs.
|
||||||
|
if (( $(stat --format='%Y' "$file") != $(stat --format='%Y' "$save_path") )); then
|
||||||
|
needs_update=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( needs_update )); then
|
||||||
# If http, use curl to grab the image.
|
# If http, use curl to grab the image.
|
||||||
if [[ "$file" =~ ^http(s|)\:\/\/ ]]; then
|
if [[ "$file" =~ ^http(s|)\:\/\/ ]]; then
|
||||||
|
|
||||||
# If failure, and is not the default image, attempt to grab the default file.
|
# If failure, and is not the default image, attempt to grab the default file.
|
||||||
# --fail suppresses writing the response body on HTTP errors; rm -f cleans up
|
# --fail suppresses writing the response body on HTTP errors; rm -f cleans up
|
||||||
# any partial file so the fallback recursion isn't blocked by the [[ ! -e ]] guard.
|
# any partial file so the fallback recursion isn't blocked by the needs_update check.
|
||||||
if ! http_code=$(curl -sf --write-out "%{http_code}" -o "$save_path" "$file") \
|
if ! http_code=$(curl -sf --write-out "%{http_code}" -o "$save_path" "$file") \
|
||||||
|| ( ((http_code!=200)) && [[ "$file" != "$icons_default_img" ]] \
|
|| ( ((http_code!=200)) && [[ "$file" != "$icons_default_img" ]] \
|
||||||
&& [[ "$file" != "$icons_default_source/$icons_default_img" ]] ); then
|
&& [[ "$file" != "$icons_default_source/$icons_default_img" ]] ); then
|
||||||
|
|
@ -123,17 +141,17 @@ image_copy() {
|
||||||
image_copy "$icons_default_img" "$file_name"
|
image_copy "$icons_default_img" "$file_name"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
# If the file exists, copy it.
|
# If the file exists, copy it preserving mtime.
|
||||||
elif [[ -f $file ]]; then
|
elif [[ -f $file ]]; then
|
||||||
cp "$file" "$save_path"
|
cp -p "$file" "$save_path"
|
||||||
else
|
else
|
||||||
# Check to see if a template file exists with the file name.
|
# Check to see if a template file exists with the file name.
|
||||||
local t_file
|
local t_file
|
||||||
t_file=$(template_file "$file")
|
t_file=$(template_file "$file")
|
||||||
# If the file exists, copy it.
|
# If the file exists, copy it preserving mtime.
|
||||||
if [[ -f $t_file ]]; then
|
if [[ -f $t_file ]]; then
|
||||||
cp "$t_file" "$save_path"
|
cp -p "$t_file" "$save_path"
|
||||||
elif [[ "$file" != "$icons_default_source/$file" ]]; then
|
elif [[ "$file" != /* ]] && [[ "$file" != "$icons_default_source/$file" ]]; then
|
||||||
# If nothing else exists, try grabbing from the default source.
|
# If nothing else exists, try grabbing from the default source.
|
||||||
image_copy "$icons_default_source/$file" "$file_name"
|
image_copy "$icons_default_source/$file" "$file_name"
|
||||||
return
|
return
|
||||||
|
|
@ -199,7 +217,7 @@ while (( $# > 0 )); do
|
||||||
|
|
||||||
# If the mirror wasn't found, quit.
|
# If the mirror wasn't found, quit.
|
||||||
if [[ -z $foundMirror ]]; then
|
if [[ -z $foundMirror ]]; then
|
||||||
echo "Unknown mirror '$1'"
|
echo "Unknown mirror '$mirror'"
|
||||||
echo
|
echo
|
||||||
print_help "$@"
|
print_help "$@"
|
||||||
fi
|
fi
|
||||||
|
|
@ -230,13 +248,13 @@ if [[ -f $PIDFILE ]]; then
|
||||||
|
|
||||||
# Check if PID is active.
|
# Check if PID is active.
|
||||||
if ps -p "$PID" >/dev/null; then
|
if ps -p "$PID" >/dev/null; then
|
||||||
log "A sync is already in progress for ${MODULE} with pid ${PID}."
|
log "A sync is already in progress (pid ${PID})."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create a new pid file for this process.
|
# Create a new pid file for this process.
|
||||||
echo $BASHPID >"$PIDFILE"
|
echo "$BASHPID" >"$PIDFILE"
|
||||||
|
|
||||||
# On exit, remove pid file.
|
# On exit, remove pid file.
|
||||||
trap 'rm -f "$PIDFILE"' EXIT
|
trap 'rm -f "$PIDFILE"' EXIT
|
||||||
|
|
@ -259,6 +277,28 @@ if (( ${#selected_mirrors[@]} == 0 )); then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure the local dashboard-icons repo is present and fresh (pulled at most weekly).
|
||||||
|
if [[ -n $icons_local_repo ]]; then
|
||||||
|
if [[ -n $icons_repo_url ]] && [[ ! -d "$icons_local_repo/.git" ]]; then
|
||||||
|
log "Cloning dashboard-icons to $icons_local_repo"
|
||||||
|
git clone --depth=1 "$icons_repo_url" "$icons_local_repo" \
|
||||||
|
|| log "Warning: failed to clone dashboard-icons, falling back to remote URLs"
|
||||||
|
elif [[ -n $icons_repo_url ]] && [[ -d "$icons_local_repo/.git" ]]; then
|
||||||
|
fetch_head="$icons_local_repo/.git/FETCH_HEAD"
|
||||||
|
if [[ ! -f "$fetch_head" ]] \
|
||||||
|
|| (( $(date +%s) - $(stat --format='%Y' "$fetch_head") > icons_repo_refresh )); then
|
||||||
|
log "Updating dashboard-icons at $icons_local_repo"
|
||||||
|
git -C "$icons_local_repo" pull --ff-only \
|
||||||
|
|| log "Warning: failed to update dashboard-icons"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prefer the local clone over the remote URL.
|
||||||
|
if [[ -d "$icons_local_repo/png" ]]; then
|
||||||
|
icons_default_source="$icons_local_repo/png"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Keep track of repos which sizes were updated for to
|
# Keep track of repos which sizes were updated for to
|
||||||
# avoid updating sizes in multi mirror situations.
|
# avoid updating sizes in multi mirror situations.
|
||||||
repo_sizes_updated=()
|
repo_sizes_updated=()
|
||||||
|
|
@ -347,7 +387,7 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
eval sync_method="\${${MODULE}_sync_method:-rsync}"
|
eval sync_method="\${${MODULE}_sync_method:-rsync}"
|
||||||
|
|
||||||
# If is this module.
|
# If is this module.
|
||||||
if [[ "${repo:?}" == "$real_dir" ]]; then
|
if [[ -n $repo ]] && [[ "$repo" == "$real_dir" ]]; then
|
||||||
found_repo=1
|
found_repo=1
|
||||||
# If QFM module, we need to determine sub path using QFM logic.
|
# If QFM module, we need to determine sub path using QFM logic.
|
||||||
elif [[ "${sync_method:?}" == "qfm" ]]; then
|
elif [[ "${sync_method:?}" == "qfm" ]]; then
|
||||||
|
|
@ -391,13 +431,13 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
read_config
|
read_config
|
||||||
|
|
||||||
# If a timestamp file exists, grab and format the date.
|
# If a timestamp file exists, grab and format the date.
|
||||||
if [[ -f ${timestamp:?} ]]; then
|
if [[ -n $timestamp ]] && [[ -f $timestamp ]]; then
|
||||||
repo_sync_time=$(date -d "@$(cat "${timestamp:?}")" '+%c')
|
repo_sync_time=$(date -d "@$(cat "$timestamp")" '+%c')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If a directory usage summary exists and we're not skipping, parse the size.
|
# If a directory usage summary exists and we're not skipping, parse the size.
|
||||||
if [[ -f ${dusum:?} ]] && ((${repo_skip:-0} == 0)); then
|
if [[ -n $dusum ]] && [[ -f $dusum ]] && ((${repo_skip:-0} == 0)); then
|
||||||
repo_size_kb=$(grep "$real_dir" "${dusum:?}" | awk '{print $1}')
|
repo_size_kb=$(grep "$real_dir" "$dusum" | awk '{print $1}')
|
||||||
if [[ -n $repo_size_kb ]]; then
|
if [[ -n $repo_size_kb ]]; then
|
||||||
totalKBytes=$((totalKBytes+repo_size_kb))
|
totalKBytes=$((totalKBytes+repo_size_kb))
|
||||||
repo_size=$(echo "$repo_size_kb*1024" | bc | numfmt --to=iec)
|
repo_size=$(echo "$repo_size_kb*1024" | bc | numfmt --to=iec)
|
||||||
|
|
@ -409,12 +449,12 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
|
|
||||||
if ((found_repo == 0)); then
|
if ((found_repo == 0)); then
|
||||||
# To allow customization of non synced modules, check each module.
|
# To allow customization of non synced modules, check each module.
|
||||||
for MODULE in ${CUSTOM_MODULES:?}; do
|
for MODULE in ${CUSTOM_MODULES:-}; do
|
||||||
# Get the repo with trailing slash removed.
|
# Get the repo with trailing slash removed.
|
||||||
eval repo="\${${MODULE}_repo%/}"
|
eval repo="\${${MODULE}_repo%/}"
|
||||||
|
|
||||||
# Confirm if this custom module is this repo, and parse configs if it is.
|
# Confirm if this custom module is this repo, and parse configs if it is.
|
||||||
if [[ "${repo:?}" == "$real_dir" ]]; then
|
if [[ -n $repo ]] && [[ "$repo" == "$real_dir" ]]; then
|
||||||
log "Found custom configurations"
|
log "Found custom configurations"
|
||||||
read_config
|
read_config
|
||||||
# Stage/prod tiers populated by mirror-promote.sh land here,
|
# Stage/prod tiers populated by mirror-promote.sh land here,
|
||||||
|
|
@ -527,7 +567,7 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
if ((dir_sizes_human_readable)); then
|
if ((dir_sizes_human_readable)); then
|
||||||
printf "%-5s %s\n" "$repo_size" "$dir_name" >> "$dir_sizes_file_path"
|
printf "%-5s %s\n" "$repo_size" "$dir_name" >> "$dir_sizes_file_path"
|
||||||
else
|
else
|
||||||
printf "%-12s %s\n" "$repo_size_kb" "$dir_name" >> "$dir_sizes_file_path"
|
printf "%-12s %s\n" "${repo_size_kb:-0}" "$dir_name" >> "$dir_sizes_file_path"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -539,7 +579,7 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
|
|
||||||
# If the index should be generated, add each section and footer.
|
# If the index should be generated, add each section and footer.
|
||||||
if ((index_generate)); then
|
if ((index_generate)); then
|
||||||
# Add all sections and remove teh temp file.
|
# Add all sections and remove the temp file.
|
||||||
for SECTION in $SECTIONS; do
|
for SECTION in $SECTIONS; do
|
||||||
cat "$index_file_temp.$SECTION" >> "$index_file_temp"
|
cat "$index_file_temp.$SECTION" >> "$index_file_temp"
|
||||||
rm -f "$index_file_temp.$SECTION"
|
rm -f "$index_file_temp.$SECTION"
|
||||||
|
|
@ -552,6 +592,8 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
if grep -q "Last Sync:" "$index_file_temp"; then
|
if grep -q "Last Sync:" "$index_file_temp"; then
|
||||||
[[ -f $index_file_path ]] && rm -f "$index_file_path"
|
[[ -f $index_file_path ]] && rm -f "$index_file_path"
|
||||||
mv "$index_file_temp" "$index_file_path"
|
mv "$index_file_temp" "$index_file_path"
|
||||||
|
else
|
||||||
|
rm -f "$index_file_temp"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -564,7 +606,7 @@ for ((i=0; i<${#selected_mirrors[@]}; i++)); do
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If we should generate the gloabl footer, do so.
|
# If we should generate the global footer, do so.
|
||||||
if ((footer_generate)); then
|
if ((footer_generate)); then
|
||||||
log "Generating footer for $mirror at $path/$footer_file_name"
|
log "Generating footer for $mirror at $path/$footer_file_name"
|
||||||
envsubst < "$(template_file footer.txt)" > "$path/$footer_file_name"
|
envsubst < "$(template_file footer.txt)" > "$path/$footer_file_name"
|
||||||
|
|
|
||||||
174
mirror-sync.sh
174
mirror-sync.sh
|
|
@ -5,7 +5,7 @@ PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:$HOME/.local/
|
||||||
|
|
||||||
# Variables for trace generation.
|
# Variables for trace generation.
|
||||||
PROGRAM="mirror-sync"
|
PROGRAM="mirror-sync"
|
||||||
VERSION="20240219"
|
VERSION="20260602"
|
||||||
TRACEHOST=$(hostname -f)
|
TRACEHOST=$(hostname -f)
|
||||||
mirror_hostname=$(hostname -f)
|
mirror_hostname=$(hostname -f)
|
||||||
DATE_STARTED=$(LC_ALL=POSIX LANG=POSIX date -u -R)
|
DATE_STARTED=$(LC_ALL=POSIX LANG=POSIX date -u -R)
|
||||||
|
|
@ -122,7 +122,7 @@ quick_fedora_mirror_install() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
)
|
) || return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Installs jigdo image tool.
|
# Installs jigdo image tool.
|
||||||
|
|
@ -180,7 +180,7 @@ EOF
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
make install
|
make install
|
||||||
)
|
) || return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,7 +211,10 @@ s5cmd_install() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extract and check that s5cmd extracted correctly.
|
# Extract and check that s5cmd extracted correctly.
|
||||||
tar -xf s5cmd.tar.gz
|
if ! tar -xf s5cmd.tar.gz; then
|
||||||
|
echo "Unable to extract s5cmd."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
if ! [[ -f s5cmd ]]; then
|
if ! [[ -f s5cmd ]]; then
|
||||||
echo "Unable to extract s5cmd."
|
echo "Unable to extract s5cmd."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -242,11 +245,11 @@ jigdo_hook() {
|
||||||
currentVersion="${currentVersion##* -> }"
|
currentVersion="${currentVersion##* -> }"
|
||||||
versionDir="$(realpath "$repo")/${currentVersion}"
|
versionDir="$(realpath "$repo")/${currentVersion}"
|
||||||
|
|
||||||
# For each archetecture, run jigdo to build iso files.
|
# For each architecture, run jigdo to build iso files.
|
||||||
for a in "$versionDir"/*/; do
|
for a in "$versionDir"/*/; do
|
||||||
arch=$(basename "$a")
|
arch=$(basename "$a")
|
||||||
|
|
||||||
# Determine what releases are needed for this archetecture.
|
# Determine what releases are needed for this architecture.
|
||||||
sets=$(cat "${repo}/project/build/${currentVersion}/${arch}")
|
sets=$(cat "${repo}/project/build/${currentVersion}/${arch}")
|
||||||
|
|
||||||
# For each set, build iso files.
|
# For each set, build iso files.
|
||||||
|
|
@ -299,7 +302,7 @@ build_trace_content() {
|
||||||
echo "Date: ${rfc822date}"
|
echo "Date: ${rfc822date}"
|
||||||
echo "Date-Started: ${DATE_STARTED}"
|
echo "Date-Started: ${DATE_STARTED}"
|
||||||
|
|
||||||
if [[ -e $TRACEFILE_MASTER ]]; then
|
if [[ -e $TRACE_MASTER_FILE ]]; then
|
||||||
echo "Archive serial: $(extract_trace_field 'Archive serial' "$TRACE_MASTER_FILE" || echo unknown )"
|
echo "Archive serial: $(extract_trace_field 'Archive serial' "$TRACE_MASTER_FILE" || echo unknown )"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -326,7 +329,7 @@ build_trace_content() {
|
||||||
echo "Trigger: ${INFO_TRIGGER}"
|
echo "Trigger: ${INFO_TRIGGER}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Depending on repo type, find archetectures supported.
|
# Depending on repo type, find architectures supported.
|
||||||
ARCH_REGEX='(source|SRPMS|amd64|mips64el|mipsel|i386|x86_64|aarch64|ppc64le|ppc64el|s390x|armhf)'
|
ARCH_REGEX='(source|SRPMS|amd64|mips64el|mipsel|i386|x86_64|aarch64|ppc64le|ppc64el|s390x|armhf)'
|
||||||
if [[ $repo_type == "deb" ]]; then
|
if [[ $repo_type == "deb" ]]; then
|
||||||
ARCH=$(find "${repo}/dists" \( -name 'Packages.*' -o -name 'Sources.*' \) 2>/dev/null |
|
ARCH=$(find "${repo}/dists" \( -name 'Packages.*' -o -name 'Sources.*' \) 2>/dev/null |
|
||||||
|
|
@ -364,18 +367,21 @@ build_trace_content() {
|
||||||
total=$(( total + bytes ))
|
total=$(( total + bytes ))
|
||||||
done
|
done
|
||||||
elif [[ -f $LOGFILE_STAGE1 ]]; then
|
elif [[ -f $LOGFILE_STAGE1 ]]; then
|
||||||
bytes=$(sed -Ene 's/(^|.* )sent ([0-9]+) bytes received ([0-9]+) bytes.*/\3/p' "$LOGFILE_STAGE1")
|
for bytes in $(sed -Ene 's/(^|.* )sent ([0-9]+) bytes received ([0-9]+) bytes.*/\3/p' "$LOGFILE_STAGE1"); do
|
||||||
total=$(( total + bytes ))
|
total=$(( total + bytes ))
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
if [[ -f $LOGFILE_STAGE2 ]]; then
|
if [[ -f $LOGFILE_STAGE2 ]]; then
|
||||||
bytes=$(sed -Ene 's/(^|.* )sent ([0-9]+) bytes received ([0-9]+) bytes.*/\3/p' "$LOGFILE_STAGE2")
|
for bytes in $(sed -Ene 's/(^|.* )sent ([0-9]+) bytes received ([0-9]+) bytes.*/\3/p' "$LOGFILE_STAGE2"); do
|
||||||
total=$(( total + bytes ))
|
total=$(( total + bytes ))
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
if (( total > 0 )); then
|
if (( total > 0 )); then
|
||||||
echo "Total bytes received in rsync: ${total}"
|
echo "Total bytes received in rsync: ${total}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Calculate time per rsync stage and print both stages if both were started.
|
# Calculate time per rsync stage and print both stages if both were started.
|
||||||
|
total_time=0
|
||||||
if [[ $sync_started ]]; then
|
if [[ $sync_started ]]; then
|
||||||
STATS_TOTAL_RSYNC_TIME1=$(( sync_ended - sync_started ))
|
STATS_TOTAL_RSYNC_TIME1=$(( sync_ended - sync_started ))
|
||||||
total_time=$STATS_TOTAL_RSYNC_TIME1
|
total_time=$STATS_TOTAL_RSYNC_TIME1
|
||||||
|
|
@ -444,6 +450,7 @@ acquire_lock() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Redirect stdout to both stdout and log file.
|
# Redirect stdout to both stdout and log file.
|
||||||
|
mkdir -p "$LOGPATH"
|
||||||
exec 1> >(tee -a "$LOGFILE")
|
exec 1> >(tee -a "$LOGFILE")
|
||||||
# Redirect errors to stdout so they also are logged.
|
# Redirect errors to stdout so they also are logged.
|
||||||
exec 2>&1
|
exec 2>&1
|
||||||
|
|
@ -465,7 +472,7 @@ acquire_lock() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create a new pid file for this process.
|
# Create a new pid file for this process.
|
||||||
echo $BASHPID >"$PIDFILE"
|
echo "$BASHPID" >"$PIDFILE"
|
||||||
|
|
||||||
# On exit, remove pid file.
|
# On exit, remove pid file.
|
||||||
trap 'rm -f "$PIDFILE"' EXIT
|
trap 'rm -f "$PIDFILE"' EXIT
|
||||||
|
|
@ -493,15 +500,15 @@ rebuild_dusum_totals() {
|
||||||
{
|
{
|
||||||
date
|
date
|
||||||
totalKBytes=0
|
totalKBytes=0
|
||||||
for MODULE in ${MODULES:?}; do
|
for _DUSUM_MODULE in ${MODULES:?}; do
|
||||||
eval dusum="\${${MODULE}_dusum:-}"
|
eval _dusum="\${${_DUSUM_MODULE}_dusum:-}"
|
||||||
if [[ -n $dusum ]] && [[ -f $dusum ]]; then
|
if [[ -n $_dusum ]] && [[ -f $_dusum ]]; then
|
||||||
while read -r size path; do
|
while read -r size path; do
|
||||||
if [[ -n $size ]]; then
|
if [[ -n $size ]]; then
|
||||||
totalKBytes=$((totalKBytes+size))
|
totalKBytes=$((totalKBytes+size))
|
||||||
printf "%-12s %s\n" "$size" "$path"
|
printf "%-12s %s\n" "$size" "$path"
|
||||||
fi
|
fi
|
||||||
done < "$dusum"
|
done < "$_dusum"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
printf "%-12s %s\n" "$totalKBytes" "total"
|
printf "%-12s %s\n" "$totalKBytes" "total"
|
||||||
|
|
@ -513,15 +520,15 @@ rebuild_dusum_totals() {
|
||||||
{
|
{
|
||||||
date
|
date
|
||||||
totalKBytes=0
|
totalKBytes=0
|
||||||
for MODULE in ${MODULES:?}; do
|
for _DUSUM_MODULE in ${MODULES:?}; do
|
||||||
eval dusum="\${${MODULE}_dusum:-}"
|
eval _dusum="\${${_DUSUM_MODULE}_dusum:-}"
|
||||||
if [[ -n $dusum ]] && [[ -f $dusum ]]; then
|
if [[ -n $_dusum ]] && [[ -f $_dusum ]]; then
|
||||||
while read -r size path; do
|
while read -r size path; do
|
||||||
if [[ -n $size ]]; then
|
if [[ -n $size ]]; then
|
||||||
totalKBytes=$((totalKBytes+size))
|
totalKBytes=$((totalKBytes+size))
|
||||||
printf "%-5s %s\n" "$(echo "$size*1024" | bc | numfmt --to=iec)" "$path"
|
printf "%-5s %s\n" "$(echo "$size*1024" | bc | numfmt --to=iec)" "$path"
|
||||||
fi
|
fi
|
||||||
done < "$dusum"
|
done < "$_dusum"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
printf "%-5s %s\n" "$(echo "$totalKBytes*1024" | bc | numfmt --to=iec)" "total"
|
printf "%-5s %s\n" "$(echo "$totalKBytes*1024" | bc | numfmt --to=iec)" "total"
|
||||||
|
|
@ -577,7 +584,7 @@ post_failed_sync() {
|
||||||
# Remove the error count file so that the count resets.
|
# Remove the error count file so that the count resets.
|
||||||
rm -f "$ERRORFILE"
|
rm -f "$ERRORFILE"
|
||||||
|
|
||||||
# Exit not to not save the updated count.
|
# Exit to not save the updated count.
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -610,20 +617,18 @@ git_sync() {
|
||||||
# Start the module.
|
# Start the module.
|
||||||
module_config "$1"
|
module_config "$1"
|
||||||
|
|
||||||
(
|
# Do a git pull within the repo folder to sync.
|
||||||
# Do a git pull within the repo folder to sync.
|
if ! cd "${repo:?}"; then
|
||||||
if ! cd "${repo:?}"; then
|
echo "Failed to access '${repo:?}' git repository."
|
||||||
echo "Failed to access '${repo:?}' git repository."
|
exit 1
|
||||||
exit 1
|
fi
|
||||||
fi
|
eval git pull ${options:+$options}
|
||||||
eval git pull "$options"
|
RT=$?
|
||||||
RT=${PIPESTATUS[0]}
|
if (( RT == 0 )); then
|
||||||
if (( RT == 0 )); then
|
post_successful_sync
|
||||||
post_successful_sync
|
else
|
||||||
else
|
post_failed_sync
|
||||||
post_failed_sync
|
fi
|
||||||
fi
|
|
||||||
)
|
|
||||||
|
|
||||||
log_end_header
|
log_end_header
|
||||||
}
|
}
|
||||||
|
|
@ -708,7 +713,7 @@ s5cmd_sync() {
|
||||||
|
|
||||||
# Run AWS client to sync the S3 bucket.
|
# Run AWS client to sync the S3 bucket.
|
||||||
eval "$sync_timeout" "$S5CMD_BIN" "$options" \
|
eval "$sync_timeout" "$S5CMD_BIN" "$options" \
|
||||||
sync "${sync_options:-}" \
|
sync ${sync_options:+$sync_options} \
|
||||||
--no-follow-symlinks \
|
--no-follow-symlinks \
|
||||||
--delete \
|
--delete \
|
||||||
"'${bucket:?}'" "'${repo:?}'"
|
"'${bucket:?}'" "'${repo:?}'"
|
||||||
|
|
@ -751,6 +756,7 @@ wget_sync() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
(
|
(
|
||||||
|
trap - EXIT
|
||||||
# Make sure the repo directory exists and we are in it.
|
# Make sure the repo directory exists and we are in it.
|
||||||
if ! [[ -e $repo ]]; then
|
if ! [[ -e $repo ]]; then
|
||||||
mkdir -p "$repo"
|
mkdir -p "$repo"
|
||||||
|
|
@ -758,6 +764,7 @@ wget_sync() {
|
||||||
|
|
||||||
if ! cd "$repo"; then
|
if ! cd "$repo"; then
|
||||||
echo "Unable to enter repo directory."
|
echo "Unable to enter repo directory."
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run wget with configured options.
|
# Run wget with configured options.
|
||||||
|
|
@ -769,6 +776,10 @@ wget_sync() {
|
||||||
post_failed_sync
|
post_failed_sync
|
||||||
fi
|
fi
|
||||||
)
|
)
|
||||||
|
RT=$?
|
||||||
|
if (( RT != 0 )); then
|
||||||
|
exit "$RT"
|
||||||
|
fi
|
||||||
|
|
||||||
log_end_header
|
log_end_header
|
||||||
}
|
}
|
||||||
|
|
@ -823,20 +834,31 @@ rsync_sync() {
|
||||||
# when we detect its needed or when last rsync was a long time ago.
|
# when we detect its needed or when last rsync was a long time ago.
|
||||||
if [[ $upstream_check ]] && (( force == 0 )); then
|
if [[ $upstream_check ]] && (( force == 0 )); then
|
||||||
now=$(date +%s)
|
now=$(date +%s)
|
||||||
last_timestamp=$(cat "${timestamp:?}")
|
if [[ ! -f ${timestamp:?} ]]; then
|
||||||
|
echo "Timestamp file not found, skipping upstream check."
|
||||||
|
else
|
||||||
|
last_timestamp=$(cat "$timestamp")
|
||||||
|
|
||||||
# If last update was not that long ago, we should check if upstream was updated recently.
|
# If last update was not that long ago, we should check if upstream was updated recently.
|
||||||
if (( now-last_timestamp < ${upstream_timestamp_min:?} )); then
|
if (( now-last_timestamp < ${upstream_timestamp_min:?} )); then
|
||||||
echo "Checking upstream's last modified."
|
echo "Checking upstream's last modified."
|
||||||
|
|
||||||
# Get the last modified date.
|
# Get the last modified date.
|
||||||
IFS=': ' read -r _ last_modified < <(curl -sI HEAD "${upstream_check:?}" | grep Last-Modified)
|
IFS=': ' read -r _ last_modified < <(curl -sI "${upstream_check:?}" | grep -i Last-Modified)
|
||||||
last_modified_unix=$(date -u +%s -d "$last_modified")
|
last_modified="${last_modified//$'\r'/}"
|
||||||
|
|
||||||
# If last modified is greater than our max age, it wasn't modified recently and we should not rsync.
|
# If last modified couldn't be determined, proceed with sync.
|
||||||
if (( now-last_modified_unix > ${upstream_max_age:-0} )); then
|
if [[ -z $last_modified ]]; then
|
||||||
echo "Skipping sync as upstream wasn't updated recently."
|
echo "Could not determine upstream last-modified, proceeding with sync."
|
||||||
exit 88
|
else
|
||||||
|
last_modified_unix=$(date -u +%s -d "$last_modified")
|
||||||
|
|
||||||
|
# If last modified is greater than our max age, it wasn't modified recently and we should not rsync.
|
||||||
|
if (( now-last_modified_unix > ${upstream_max_age:-0} )); then
|
||||||
|
echo "Skipping sync as upstream wasn't updated recently."
|
||||||
|
exit 88
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -844,19 +866,26 @@ rsync_sync() {
|
||||||
# If a time file check was defined, and check if needed.
|
# If a time file check was defined, and check if needed.
|
||||||
if [[ ${time_file_check:-} ]] && (( force == 0 )); then
|
if [[ ${time_file_check:-} ]] && (( force == 0 )); then
|
||||||
now=$(date +%s)
|
now=$(date +%s)
|
||||||
last_timestamp=$(cat "${timestamp:?}")
|
if [[ ! -f ${timestamp:?} ]]; then
|
||||||
|
echo "Timestamp file not found, skipping time file check."
|
||||||
|
else
|
||||||
|
last_timestamp=$(cat "$timestamp")
|
||||||
|
|
||||||
# Only check time file if the timestamp was recently updated.
|
# Only check time file if the timestamp was recently updated.
|
||||||
if (( now-last_timestamp < ${upstream_timestamp_min:?} )); then
|
if (( now-last_timestamp < ${upstream_timestamp_min:?} )); then
|
||||||
echo "Checking if time file has changed since last sync."
|
echo "Checking if time file has changed since last sync."
|
||||||
checkresult=$($sync_timeout rsync \
|
checkresult=$($sync_timeout rsync \
|
||||||
--no-motd \
|
--no-motd \
|
||||||
--dry-run \
|
--dry-run \
|
||||||
--out-format="%n" \
|
--out-format="%n" \
|
||||||
"${source:?}/${time_file_check:?}" "${repo:?}/${time_file_check:?}")
|
"${source:?}/${time_file_check:?}" "${repo:?}/${time_file_check:?}")
|
||||||
if [[ -z $checkresult ]]; then
|
rsync_rt=$?
|
||||||
echo "The time file has not changed since last sync, we are not updating at this time."
|
if (( rsync_rt != 0 )); then
|
||||||
exit 88
|
echo "time_file_check rsync failed (exit ${rsync_rt}), proceeding with sync."
|
||||||
|
elif [[ -z $checkresult ]]; then
|
||||||
|
echo "The time file has not changed since last sync, we are not updating at this time."
|
||||||
|
exit 88
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -882,13 +911,10 @@ rsync_sync() {
|
||||||
touch "$mirror_update_file"
|
touch "$mirror_update_file"
|
||||||
LOGFILE_STAGE1="${LOGFILE}.stage1"
|
LOGFILE_STAGE1="${LOGFILE}.stage1"
|
||||||
echo -n > "$LOGFILE_STAGE1"
|
echo -n > "$LOGFILE_STAGE1"
|
||||||
LOGFILE_STAGE2="${LOGFILE}.stage2"
|
|
||||||
echo -n > "$LOGFILE_STAGE2"
|
|
||||||
|
|
||||||
# Run the rsync. Using eval here so extra_args expands and is used as arguments.
|
# Run the rsync. Using eval here so extra_args expands and is used as arguments.
|
||||||
stage1_started=$(date +%s)
|
stage1_started=$(date +%s)
|
||||||
eval "$sync_timeout" rsync -avH \
|
eval "$sync_timeout" rsync -avH \
|
||||||
--human-readable \
|
|
||||||
--progress \
|
--progress \
|
||||||
--safe-links \
|
--safe-links \
|
||||||
--delay-updates \
|
--delay-updates \
|
||||||
|
|
@ -900,11 +926,11 @@ rsync_sync() {
|
||||||
--exclude "Archive-Update-in-Progress-${mirror_hostname:?}" \
|
--exclude "Archive-Update-in-Progress-${mirror_hostname:?}" \
|
||||||
--exclude "project/trace/${mirror_hostname:?}" \
|
--exclude "project/trace/${mirror_hostname:?}" \
|
||||||
"'${source:?}'" "'${repo:?}'" | tee -a "$LOGFILE_STAGE1"
|
"'${source:?}'" "'${repo:?}'" | tee -a "$LOGFILE_STAGE1"
|
||||||
RT=${PIPESTATUS[0]}
|
|
||||||
stage1_ended=$(date +%s)
|
stage1_ended=$(date +%s)
|
||||||
|
|
||||||
# Check if run was successful.
|
# Check if run was successful.
|
||||||
if [[ $(grep -c '^total size is' "$LOGFILE_STAGE1") -ne 1 ]]; then
|
if [[ $(grep -c '^total size is' "$LOGFILE_STAGE1") -ne 1 ]]; then
|
||||||
|
rm -f "$mirror_update_file"
|
||||||
post_failed_sync
|
post_failed_sync
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -939,6 +965,8 @@ rsync_sync() {
|
||||||
|
|
||||||
# Add stage 2 options from configurations.
|
# Add stage 2 options from configurations.
|
||||||
extra_args="${options_stage2:-}"
|
extra_args="${options_stage2:-}"
|
||||||
|
LOGFILE_STAGE2="${LOGFILE}.stage2"
|
||||||
|
echo -n > "$LOGFILE_STAGE2"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Running rsync stage 2:"
|
echo "Running rsync stage 2:"
|
||||||
|
|
@ -946,7 +974,6 @@ rsync_sync() {
|
||||||
# Run the rsync. Using eval here so extra_args expands and is used as arguments.
|
# Run the rsync. Using eval here so extra_args expands and is used as arguments.
|
||||||
stage2_started=$(date +%s)
|
stage2_started=$(date +%s)
|
||||||
eval "$sync_timeout" rsync -avH \
|
eval "$sync_timeout" rsync -avH \
|
||||||
--human-readable \
|
|
||||||
--progress \
|
--progress \
|
||||||
--safe-links \
|
--safe-links \
|
||||||
--delete \
|
--delete \
|
||||||
|
|
@ -960,11 +987,11 @@ rsync_sync() {
|
||||||
--exclude "Archive-Update-in-Progress-${mirror_hostname:?}" \
|
--exclude "Archive-Update-in-Progress-${mirror_hostname:?}" \
|
||||||
--exclude "project/trace/${mirror_hostname:?}" \
|
--exclude "project/trace/${mirror_hostname:?}" \
|
||||||
"'${source:?}'" "'${repo:?}'" | tee -a "$LOGFILE_STAGE2"
|
"'${source:?}'" "'${repo:?}'" | tee -a "$LOGFILE_STAGE2"
|
||||||
RT=${PIPESTATUS[0]}
|
|
||||||
stage2_ended=$(date +%s)
|
stage2_ended=$(date +%s)
|
||||||
|
|
||||||
# Check if run was successful.
|
# Check if run was successful.
|
||||||
if [[ $(grep -c '^total size is' "$LOGFILE_STAGE2") -ne 1 ]]; then
|
if [[ $(grep -c '^total size is' "$LOGFILE_STAGE2") -ne 1 ]]; then
|
||||||
|
rm -f "$mirror_update_file"
|
||||||
post_failed_sync
|
post_failed_sync
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -983,7 +1010,7 @@ rsync_sync() {
|
||||||
save_trace_file
|
save_trace_file
|
||||||
fi
|
fi
|
||||||
rm -f "$LOGFILE_STAGE1"
|
rm -f "$LOGFILE_STAGE1"
|
||||||
rm -f "$LOGFILE_STAGE2"
|
[[ -n ${LOGFILE_STAGE2:-} ]] && rm -f "$LOGFILE_STAGE2"
|
||||||
|
|
||||||
# Remove archive update file.
|
# Remove archive update file.
|
||||||
rm -f "$mirror_update_file"
|
rm -f "$mirror_update_file"
|
||||||
|
|
@ -1033,13 +1060,6 @@ quick_fedora_mirror_sync() {
|
||||||
eval filterexp="\$${MODULE}_filterexp"
|
eval filterexp="\$${MODULE}_filterexp"
|
||||||
eval rsync_options="\$${MODULE}_rsync_options"
|
eval rsync_options="\$${MODULE}_rsync_options"
|
||||||
|
|
||||||
# If configuration is not set, exit.
|
|
||||||
if [[ ! $repo ]]; then
|
|
||||||
echo "No configuration exists for ${MODULE}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
log_start_header
|
|
||||||
|
|
||||||
# Install QFM if not already installed.
|
# Install QFM if not already installed.
|
||||||
quick_fedora_mirror_install
|
quick_fedora_mirror_install
|
||||||
|
|
||||||
|
|
@ -1088,11 +1108,13 @@ EOF
|
||||||
eval "$sync_timeout" "$QFM_BIN" \
|
eval "$sync_timeout" "$QFM_BIN" \
|
||||||
-c "'$conf_path'" \
|
-c "'$conf_path'" \
|
||||||
"$extra_args" | tee -a "$LOGFILE_SYNC"
|
"$extra_args" | tee -a "$LOGFILE_SYNC"
|
||||||
RT=${PIPESTATUS[0]}
|
|
||||||
sync_ended=$(date +%s)
|
sync_ended=$(date +%s)
|
||||||
|
|
||||||
# Check if run was successful.
|
# Check if run was successful.
|
||||||
if [[ $(grep -c '^total size is' "$LOGFILE_SYNC") -lt 1 ]]; then
|
if ! grep -q '^total size is' "$LOGFILE_SYNC"; then
|
||||||
|
for module in $modules; do
|
||||||
|
rm -f "$docroot$(module_dir "$module")/Archive-Update-in-Progress-${mirror_hostname:?}"
|
||||||
|
done
|
||||||
post_failed_sync
|
post_failed_sync
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue