mirror of
https://github.com/MatthewL246/pretendo-docker.git
synced 2026-09-13 13:55:10 -05:00
Update and rename scripts to be more user-friendly
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
create_community_script=$(cat "$git_base/scripts/run-in-container/create-juxt-community.js")
|
||||
|
||||
docker compose up -d juxtaposition-ui
|
||||
|
||||
printf "Enter the community name you want to create: "
|
||||
read -r community_name
|
||||
printf "Enter the community description: "
|
||||
read -r community_description
|
||||
printf "Enter the title IDs you want to add (comma separated, no spaces): "
|
||||
read -r community_title_ids
|
||||
printf "Enter a path for the community icon: "
|
||||
read -r community_icon_path
|
||||
docker compose cp "$community_icon_path" juxtaposition-ui:/tmp/icon
|
||||
printf "Enter a path for the community banner: "
|
||||
read -r community_banner_path
|
||||
docker compose cp "$community_banner_path" juxtaposition-ui:/tmp/banner
|
||||
|
||||
docker compose exec juxtaposition-ui node -e "$create_community_script" "$community_name" "$community_description" "$community_title_ids"
|
||||
@@ -3,18 +3,31 @@
|
||||
set -eu
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
|
||||
if [ ! -f "$git_base/environment/system.local.env" ]; then
|
||||
echo "Missing environment file system.local.env. Did you run setup-environment.sh?"
|
||||
exit 1
|
||||
fi
|
||||
. "$git_base/environment/system.local.env"
|
||||
if [ -z "${WIIU_IP+x}" ]; then
|
||||
echo "Missing environment variable WIIU_IP. Did you specify a Wii U IP address when you ran setup-environment.sh?"
|
||||
echo "Continuing without automatic FTP upload."
|
||||
fi
|
||||
|
||||
cd "$git_base/repos/Inkay"
|
||||
|
||||
# Get the current certificate (requires mitmproxy-pretendo to have been run at
|
||||
# least once)
|
||||
mitmproxy_cert=$(docker run -it --rm -v pretendo-network_mitmproxy-pretendo-data:/mnt busybox cat /mnt/mitmproxy-ca-cert.pem)
|
||||
echo "$mitmproxy_cert" | tee ./data/ca.pem
|
||||
docker compose up -d mitmproxy-pretendo
|
||||
|
||||
# Get the current certificate
|
||||
docker compose cp mitmproxy-pretendo:/home/mitmproxy/.mitmproxy/mitmproxy-ca-cert.pem ./data/ca.pem
|
||||
|
||||
# Set up the Inkay build environment and then build the patches
|
||||
docker build . -t inkay-build
|
||||
docker run -it --rm -v .:/app -w /app inkay-build
|
||||
echo "Inkay patches built successfully at $(pwd)/Inkay-pretendo.wps"
|
||||
|
||||
# Finally, upload the new Inkay patches to the Wii U
|
||||
ftp -u ftp://user:pass@"$WIIU_IP"/fs/vol/external01/wiiu/environments/aroma/plugins/Inkay-pretendo.wps ./Inkay-pretendo.wps
|
||||
echo "Reboot your Wii U now to apply the new patches."
|
||||
# Upload the new Inkay patches to the Wii U
|
||||
if [ -n "${WIIU_IP+x}" ]; then
|
||||
ftp -u "ftp://user:pass@$WIIU_IP/fs/vol/external01/wiiu/environments/aroma/plugins/Inkay-pretendo.wps" ./Inkay-pretendo.wps
|
||||
echo "Reboot your Wii U now to apply the new patches."
|
||||
fi
|
||||
|
||||
29
scripts/create-juxt-community.sh
Executable file
29
scripts/create-juxt-community.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
create_community_script=$(cat "$git_base/scripts/run-in-container/create-juxt-community.js")
|
||||
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "Usage: $0 <name> <description> <comma-separated title IDs> [icon image path] [banner image path]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up title IDs by removing non-alphanumeric characters, but keep commas
|
||||
title_ids=$(echo "$3" | tr -dc "a-zA-Z0-9,")
|
||||
|
||||
docker compose up -d juxtaposition-ui
|
||||
|
||||
icon_path=
|
||||
if [ "$#" -ge 4 ]; then
|
||||
docker compose cp "$4" juxtaposition-ui:/tmp/icon
|
||||
icon_path="/tmp/icon"
|
||||
fi
|
||||
banner_path=
|
||||
if [ "$#" -eq 5 ]; then
|
||||
docker compose cp "$5" juxtaposition-ui:/tmp/banner
|
||||
banner_path="/tmp/banner"
|
||||
fi
|
||||
|
||||
docker compose exec juxtaposition-ui node -e "$create_community_script" "$1" "$2" "$title_ids" "$icon_path" "$banner_path"
|
||||
@@ -12,9 +12,9 @@ docker compose up -d mongodb
|
||||
# This needs to be run after it initializes.
|
||||
# https://github.com/docker-library/mongo/issues/339
|
||||
|
||||
while ! docker compose exec mongodb mongosh --eval "db.adminCommand('ping')"; do
|
||||
while ! docker compose exec mongodb mongosh --eval "db.adminCommand('ping')" >/dev/null 2>&1; do
|
||||
echo "Waiting for mongodb to be ready..."
|
||||
sleep 1
|
||||
sleep 2
|
||||
done
|
||||
|
||||
docker compose exec mongodb mongosh --eval "$mongodb_init_script"
|
||||
|
||||
14
scripts/make-pnid-dev.sh
Executable file
14
scripts/make-pnid-dev.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
update_pnid_access_level_script=$(cat "$git_base/scripts/run-in-container/make-pnid-dev.js")
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 <PNID to give developer access>"
|
||||
exit 1
|
||||
fi
|
||||
echo "Giving developer access to PNID $1..."
|
||||
|
||||
docker compose exec account node -e "$update_pnid_access_level_script" "$1"
|
||||
@@ -1,4 +1,4 @@
|
||||
// This should run in the juxtaposition-ui container
|
||||
// This should be evaled in the juxtaposition-ui container
|
||||
const mongoose = require("mongoose");
|
||||
const { COMMUNITY } = require("./src/models/communities");
|
||||
const fs = require("fs").promises;
|
||||
@@ -12,19 +12,22 @@ const s3 = new S3({
|
||||
});
|
||||
|
||||
async function runAsync() {
|
||||
await connect();
|
||||
|
||||
if (process.argv.length !== 4) {
|
||||
console.log("<name> <description> <comma-separated title IDs>");
|
||||
if (process.argv.length < 4) {
|
||||
console.log(
|
||||
"Usage: <name> <description> <comma-separated title IDs> [icon image path] [banner image path]"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await connect();
|
||||
|
||||
await createMainCommunity(
|
||||
1,
|
||||
process.argv[1],
|
||||
process.argv[2],
|
||||
process.argv[3].split(","),
|
||||
"/tmp/icon",
|
||||
"/tmp/banner"
|
||||
process.argv[4],
|
||||
process.argv[5]
|
||||
);
|
||||
|
||||
await mongoose.connection.close();
|
||||
@@ -86,45 +89,55 @@ async function createMainCommunity(
|
||||
|
||||
async function uploadAssets(community_id, iconPath, bannerPath) {
|
||||
console.log("Uploading assets for community " + community_id);
|
||||
const sizes = [32, 64, 128];
|
||||
const iconBuffer = await fs.readFile(iconPath);
|
||||
for (const size of sizes) {
|
||||
const resizedIconBuffer = await sharp(iconBuffer)
|
||||
.resize(size, size, {
|
||||
fit: "cover",
|
||||
position: "center",
|
||||
})
|
||||
.png({ quality: 80 })
|
||||
.toBuffer();
|
||||
if (iconPath) {
|
||||
console.log("Uploading icon from " + iconPath);
|
||||
const sizes = [32, 64, 128];
|
||||
const iconBuffer = await fs.readFile(iconPath);
|
||||
for (const size of sizes) {
|
||||
const resizedIconBuffer = await sharp(iconBuffer)
|
||||
.resize(size, size, {
|
||||
fit: "cover",
|
||||
position: "center",
|
||||
})
|
||||
.png({ quality: 80 })
|
||||
.toBuffer();
|
||||
|
||||
const uploadParams = {
|
||||
Bucket: "pn-cdn",
|
||||
Key: `icons/${community_id}/${size}.png`,
|
||||
Body: resizedIconBuffer,
|
||||
ACL: "public-read",
|
||||
ContentType: "image/png",
|
||||
};
|
||||
await s3.putObject(uploadParams).promise();
|
||||
const uploadParams = {
|
||||
Bucket: "pn-cdn",
|
||||
Key: `icons/${community_id}/${size}.png`,
|
||||
Body: resizedIconBuffer,
|
||||
ACL: "public-read",
|
||||
ContentType: "image/png",
|
||||
};
|
||||
await s3.putObject(uploadParams).promise();
|
||||
}
|
||||
} else {
|
||||
console.log("No icon path specified, skipping icon upload.");
|
||||
}
|
||||
|
||||
const consoles = ["WiiU", "3DS"];
|
||||
const bannerBuffer = await fs.readFile(bannerPath);
|
||||
for (const console of consoles) {
|
||||
const resizedBannerBuffer = await sharp(bannerBuffer)
|
||||
.resize(1280, 180, {
|
||||
fit: "cover",
|
||||
position: "center",
|
||||
})
|
||||
.png({ quality: 80 })
|
||||
.toBuffer();
|
||||
if (bannerPath) {
|
||||
console.log("Uploading banner from " + bannerPath);
|
||||
const consoles = ["WiiU", "3DS"];
|
||||
const bannerBuffer = await fs.readFile(bannerPath);
|
||||
for (const console of consoles) {
|
||||
const resizedBannerBuffer = await sharp(bannerBuffer)
|
||||
.resize(1280, 180, {
|
||||
fit: "cover",
|
||||
position: "center",
|
||||
})
|
||||
.png({ quality: 80 })
|
||||
.toBuffer();
|
||||
|
||||
const uploadParams = {
|
||||
Bucket: "pn-cdn",
|
||||
Key: `headers/${community_id}/${console}.png`,
|
||||
Body: resizedBannerBuffer,
|
||||
ACL: "public-read",
|
||||
ContentType: "image/png",
|
||||
};
|
||||
await s3.putObject(uploadParams).promise();
|
||||
const uploadParams = {
|
||||
Bucket: "pn-cdn",
|
||||
Key: `headers/${community_id}/${console}.png`,
|
||||
Body: resizedBannerBuffer,
|
||||
ACL: "public-read",
|
||||
ContentType: "image/png",
|
||||
};
|
||||
await s3.putObject(uploadParams).promise();
|
||||
}
|
||||
} else {
|
||||
console.log("No banner path specified, skipping banner upload.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
// This should run in the account container
|
||||
// This should be evaled in the account container
|
||||
const mongoose = require("mongoose");
|
||||
const { connect } = require("./dist/database");
|
||||
const { PNID } = require("./dist/models/pnid");
|
||||
|
||||
async function runAsync() {
|
||||
if (process.argv.length < 2) {
|
||||
console.log("Usage: <PNID username>");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await connect();
|
||||
|
||||
if (process.argv[1]) {
|
||||
const pnid = await PNID.findOne({
|
||||
usernameLower: process.argv[1].toLowerCase(),
|
||||
});
|
||||
if (pnid) {
|
||||
await updatePnidAccessLevel(pnid, 3, "dev");
|
||||
} else {
|
||||
console.log(`No PNID found for username ${process.argv[1]}.`);
|
||||
}
|
||||
const pnid = await PNID.findOne({
|
||||
usernameLower: process.argv[1].toLowerCase(),
|
||||
});
|
||||
if (pnid) {
|
||||
await updatePnidAccessLevel(pnid, 3, "dev");
|
||||
} else {
|
||||
console.log("No username given, skipping update.");
|
||||
console.log(`No PNID found for username ${process.argv[1]}.`);
|
||||
await mongoose.connection.close();
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
await mongoose.connection.close();
|
||||
@@ -6,7 +6,5 @@ databases="friends"
|
||||
|
||||
for database in $databases; do
|
||||
echo "Creating database: $database"
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
|
||||
CREATE DATABASE $database;
|
||||
EOSQL
|
||||
psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "CREATE DATABASE $database;"
|
||||
done
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// This should run in the account container
|
||||
// This should be evaled in the account container
|
||||
const mongoose = require("mongoose");
|
||||
const { connect } = require("./dist/database");
|
||||
const { Server } = require("./dist/models/server");
|
||||
@@ -1,4 +1,4 @@
|
||||
// This should run in the miiverse-api container
|
||||
// This should be evaled in the miiverse-api container
|
||||
const mongoose = require("mongoose");
|
||||
const { connect } = require("./dist/database");
|
||||
const { Endpoint } = require("./dist/models/endpoint");
|
||||
@@ -7,6 +7,7 @@ async function runAsync() {
|
||||
await connect();
|
||||
await resetEndpoints();
|
||||
|
||||
// These are static and always use the same domains
|
||||
await createEndpoint(
|
||||
0,
|
||||
"dev",
|
||||
@@ -41,10 +42,8 @@ async function createEndpoint(
|
||||
const newEndpoint = new Endpoint({
|
||||
status: status,
|
||||
server_access_level: server_access_level,
|
||||
// Unused
|
||||
topics: true,
|
||||
// Unused
|
||||
guest_access: true,
|
||||
topics: true, // Unused
|
||||
guest_access: true, // Unused
|
||||
host: host,
|
||||
api_host: api_host,
|
||||
portal_host: portal_host,
|
||||
@@ -2,25 +2,46 @@
|
||||
|
||||
set -eu
|
||||
|
||||
# Stop all running containers so the new environment variables can be applied
|
||||
docker compose down
|
||||
|
||||
generate_password() {
|
||||
length=$1
|
||||
tr -dc 'a-zA-Z0-9' </dev/urandom | fold -w "$length" | head -n 1
|
||||
tr -dc "a-zA-Z0-9" </dev/urandom | fold -w "$length" | head -n 1
|
||||
}
|
||||
|
||||
generate_hex() {
|
||||
length=$1
|
||||
tr -dc 'A-F0-9' </dev/urandom | fold -w "$length" | head -n 1
|
||||
tr -dc "A-F0-9" </dev/urandom | fold -w "$length" | head -n 1
|
||||
}
|
||||
|
||||
# Validate arguments
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 <server IP address> [Wii U IP address]"
|
||||
exit 1
|
||||
fi
|
||||
server_ip=$1
|
||||
wiiu_ip=
|
||||
if [ "$#" -ge 2 ]; then
|
||||
wiiu_ip=$2
|
||||
fi
|
||||
|
||||
echo "Setting up local environment variables..."
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
cd "$git_base/environment"
|
||||
|
||||
rm ./*.local.env || true
|
||||
firstrun=true
|
||||
if ls ./*.local.env 1>/dev/null 2>&1; then
|
||||
echo "Local environment files already exist. They will be overwritten if you continue."
|
||||
printf "Continue? [y/N] "
|
||||
read -r continue
|
||||
if [ "$continue" != "Y" ] && [ "$continue" != "y" ]; then
|
||||
echo "Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker compose down
|
||||
rm ./*.local.env
|
||||
firstrun=false
|
||||
fi
|
||||
|
||||
# Generate an AES-256-CBC key for account server tokens
|
||||
account_aes_key=$(generate_hex 64)
|
||||
@@ -36,7 +57,7 @@ echo "PN_FRIENDS_ACCOUNT_GRPC_API_KEY=$account_grpc_api_key" >>./friends.local.e
|
||||
echo "PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_API_KEY=$account_grpc_api_key" >>./miiverse-api.local.env
|
||||
echo "JUXT_CONFIG_GRPC_ACCOUNT_API_KEY=$account_grpc_api_key" >>./juxtaposition-ui.local.env
|
||||
|
||||
# Generate secret key for MinIO
|
||||
# Generate a secret key for MinIO
|
||||
minio_secret_key=$(generate_password 32)
|
||||
echo "MINIO_ROOT_PASSWORD=$minio_secret_key" >>./minio.local.env
|
||||
echo "PN_ACT_CONFIG_S3_ACCESS_SECRET=$minio_secret_key" >>./account.local.env
|
||||
@@ -52,7 +73,8 @@ postgres_password=$(generate_password 32)
|
||||
echo "POSTGRES_PASSWORD=$postgres_password" >>./postgres.local.env
|
||||
echo "PN_FRIENDS_CONFIG_DATABASE_URI=postgres://postgres_pretendo:$postgres_password@postgres/friends?sslmode=disable" >>./friends.local.env
|
||||
|
||||
# Generate a Kerberos password and a gRPC API key for the friends server
|
||||
# Generate a Kerberos password, a gRPC API key, and an AES key for the friends
|
||||
# server
|
||||
friends_kerberos_password=$(generate_password 32)
|
||||
echo "PN_FRIENDS_CONFIG_KERBEROS_PASSWORD=$friends_kerberos_password" >>./friends.local.env
|
||||
friends_api_key=$(generate_password 32)
|
||||
@@ -72,23 +94,26 @@ miiverse_aes_key=$(generate_hex 64)
|
||||
echo "PN_MIIVERSE_API_CONFIG_AES_KEY=$miiverse_aes_key" >>./miiverse-api.local.env
|
||||
echo "JUXT_CONFIG_AES_KEY=$miiverse_aes_key" >>./juxtaposition-ui.local.env
|
||||
|
||||
# Get the computer IP address
|
||||
printf "What is your server's IP address? It must be accessible to your consoles: "
|
||||
read -r server_ip
|
||||
# Set up the server IP address
|
||||
echo "Using server IP address $server_ip."
|
||||
echo "SERVER_IP=$server_ip" >>./system.local.env
|
||||
echo "PN_FRIENDS_SECURE_SERVER_HOST=$server_ip" >>./friends.local.env
|
||||
echo "PN_WIIU_CHAT_SECURE_SERVER_LOCATION=$server_ip" >>./wiiu-chat.local.env
|
||||
|
||||
# Get the Wii U IP address
|
||||
printf "Enter your Wii U's IP address: "
|
||||
read -r wiiu_ip
|
||||
echo "WIIU_IP=$wiiu_ip" >>./system.local.env
|
||||
if [ -n "$wiiu_ip" ]; then
|
||||
echo "Using Wii U IP address $wiiu_ip."
|
||||
echo "WIIU_IP=$wiiu_ip" >>./system.local.env
|
||||
else
|
||||
echo "Skipping Wii U IP address."
|
||||
fi
|
||||
|
||||
echo "Successfully set up environment."
|
||||
|
||||
# Some things need to be updated with the new environment variables and secrets
|
||||
echo "Running necessary scripts..."
|
||||
"$git_base"/scripts/update-postgres-password.sh
|
||||
"$git_base"/scripts/update-account-servers-database.sh
|
||||
|
||||
docker compose down
|
||||
if [ "$firstrun" = false ]; then
|
||||
echo "Running necessary container update scripts..."
|
||||
"$git_base"/scripts/update-postgres-password.sh
|
||||
"$git_base"/scripts/update-account-servers-database.sh
|
||||
docker compose down
|
||||
fi
|
||||
|
||||
@@ -18,8 +18,8 @@ for dir in "$git_base/patches/"*; do
|
||||
cd "$git_base/repos/$subdir"
|
||||
|
||||
for patch in "$git_base/patches/$subdir"/*; do
|
||||
echo "Applying patch $patch..."
|
||||
git apply "$patch" -v
|
||||
echo "Applying patch $subdir/$(basename "$patch")..."
|
||||
git apply "$patch"
|
||||
git add .
|
||||
num_patches=$((num_patches + 1))
|
||||
done
|
||||
|
||||
@@ -2,19 +2,21 @@
|
||||
|
||||
set -eu
|
||||
|
||||
null_aes_key=""
|
||||
for _ in $(seq 1 64); do
|
||||
null_aes_key="${null_aes_key}0"
|
||||
done
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
create_server_script=$(cat "$git_base/scripts/run-in-container/create-server-in-database.js")
|
||||
update_pnid_access_level_script=$(cat "$git_base/scripts/run-in-container/update-pnid-access-level-in-database.js")
|
||||
create_endpoint_script=$(cat "$git_base/scripts/run-in-container/create-endpoint-in-database.js")
|
||||
create_server_script=$(cat "$git_base/scripts/run-in-container/update-account-servers-database.js")
|
||||
|
||||
necessary_environment="friends miiverse-api wiiu-chat"
|
||||
if [ ! -f "$git_base/environment/system.local.env" ]; then
|
||||
echo "Missing environment file system.local.env. Did you run setup-environment.sh?"
|
||||
exit 1
|
||||
fi
|
||||
. "$git_base/environment/system.local.env"
|
||||
for environment in $necessary_environment; do
|
||||
|
||||
necessary_environment_files="friends miiverse-api wiiu-chat"
|
||||
for environment in $necessary_environment_files; do
|
||||
if [ ! -f "$git_base/environment/$environment.local.env" ]; then
|
||||
echo "Missing environment file $environment.local.env. Did you run setup-environment.sh?"
|
||||
exit 1
|
||||
fi
|
||||
. "$git_base/environment/$environment.env"
|
||||
. "$git_base/environment/$environment.local.env"
|
||||
done
|
||||
@@ -27,11 +29,3 @@ docker compose exec -e SERVER_IP="$SERVER_IP" \
|
||||
-e MIIVERSE_AES_KEY="$PN_MIIVERSE_API_CONFIG_AES_KEY" \
|
||||
-e WIIU_CHAT_PORT="$PN_WIIU_CHAT_AUTHENTICATION_SERVER_PORT" \
|
||||
account node -e "$create_server_script"
|
||||
|
||||
printf "Enter the PNID you want to give dev access to: "
|
||||
read -r dev_pnid
|
||||
docker compose exec account node -e "$update_pnid_access_level_script" "$dev_pnid"
|
||||
|
||||
docker compose up -d miiverse-api
|
||||
|
||||
docker compose exec miiverse-api node -e "$create_endpoint_script"
|
||||
|
||||
10
scripts/update-miiverse-endpoints.sh
Executable file
10
scripts/update-miiverse-endpoints.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
create_endpoint_script=$(cat "$git_base/scripts/run-in-container/update-miiverse-endpoints.js")
|
||||
|
||||
docker compose up -d miiverse-api
|
||||
|
||||
docker compose exec miiverse-api node -e "$create_endpoint_script"
|
||||
@@ -3,6 +3,10 @@
|
||||
set -eu
|
||||
|
||||
git_base=$(git rev-parse --show-toplevel)
|
||||
if [ ! -f "$git_base/environment/postgres.local.env" ]; then
|
||||
echo "Missing environment file postgres.local.env. Did you run setup-environment.sh?"
|
||||
exit 1
|
||||
fi
|
||||
. "$git_base/environment/postgres.env"
|
||||
. "$git_base/environment/postgres.local.env"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user