Compare commits
No commits in common. "ba24b874fc6f32034b43f97366cbb723c9e23864" and "6c9b0f96a0bca0d2a30757eccd0b963a1c11a189" have entirely different histories.
ba24b874fc
...
6c9b0f96a0
71
CLAUDE.md
71
CLAUDE.md
@ -28,16 +28,10 @@ gradle build
|
|||||||
# Creates jrunner/build/distributions/jrunner.zip
|
# Creates jrunner/build/distributions/jrunner.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
Local install for testing (recommended):
|
Deploy to /opt (as documented in readme.md):
|
||||||
```bash
|
```bash
|
||||||
./gradlew installDist
|
sudo unzip jrunner/build/distributions/jrunner.zip -d /opt/
|
||||||
# Creates executable at jrunner/build/install/jrunner/bin/jrunner
|
sudo ln -sf /opt/jrunner/bin/jrunner /usr/local/bin/jrunner
|
||||||
```
|
|
||||||
|
|
||||||
Deploy using interactive script:
|
|
||||||
```bash
|
|
||||||
./deploy.sh
|
|
||||||
# Choose: 1) Local install, 2) Global install to /opt, 3) Custom directory
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
@ -45,33 +39,7 @@ Deploy using interactive script:
|
|||||||
### Single-File Design
|
### Single-File Design
|
||||||
The entire application logic resides in `jrunner/src/main/java/jrunner/jrunner.java`. This is a monolithic command-line tool with no abstraction layers or separate modules.
|
The entire application logic resides in `jrunner/src/main/java/jrunner/jrunner.java`. This is a monolithic command-line tool with no abstraction layers or separate modules.
|
||||||
|
|
||||||
### Dual Mode Operation (v1.1+)
|
|
||||||
|
|
||||||
The tool operates in two modes:
|
|
||||||
|
|
||||||
**Query Mode** (new in v1.1):
|
|
||||||
- Activates automatically when destination flags are not provided
|
|
||||||
- Outputs query results to stdout in CSV or TSV format
|
|
||||||
- Silent operation - no diagnostic output, just clean data
|
|
||||||
- Designed for piping to visidata, pspg, less, or other data tools
|
|
||||||
- Format controlled by -f flag (csv or tsv)
|
|
||||||
|
|
||||||
**Migration Mode** (original functionality):
|
|
||||||
- Activates when destination flags are provided
|
|
||||||
- Reads from source, writes to destination with batched INSERTs
|
|
||||||
- Shows progress counters and timing information
|
|
||||||
|
|
||||||
### Data Flow
|
### Data Flow
|
||||||
|
|
||||||
**Query Mode:**
|
|
||||||
1. Parse command-line arguments (-scu, -scn, -scp for source)
|
|
||||||
2. Read SQL query from file specified by -sq flag
|
|
||||||
3. Connect to source database via JDBC
|
|
||||||
4. Execute source query and fetch results (fetch size: 10,000 rows)
|
|
||||||
5. Output results to stdout in CSV or TSV format
|
|
||||||
6. Close connection and exit
|
|
||||||
|
|
||||||
**Migration Mode:**
|
|
||||||
1. Parse command-line arguments (-scu, -scn, -scp for source; -dcu, -dcn, -dcp for destination)
|
1. Parse command-line arguments (-scu, -scn, -scp for source; -dcu, -dcn, -dcp for destination)
|
||||||
2. Read SQL query from file specified by -sq flag
|
2. Read SQL query from file specified by -sq flag
|
||||||
3. Connect to source and destination databases via JDBC
|
3. Connect to source and destination databases via JDBC
|
||||||
@ -100,36 +68,23 @@ Command-line flags:
|
|||||||
- `-scu` - source JDBC URL
|
- `-scu` - source JDBC URL
|
||||||
- `-scn` - source username
|
- `-scn` - source username
|
||||||
- `-scp` - source password
|
- `-scp` - source password
|
||||||
- `-dcu` - destination JDBC URL (migration mode only)
|
- `-dcu` - destination JDBC URL
|
||||||
- `-dcn` - destination username (migration mode only)
|
- `-dcn` - destination username
|
||||||
- `-dcp` - destination password (migration mode only)
|
- `-dcp` - destination password
|
||||||
- `-sq` - path to source SQL query file
|
- `-sq` - path to source SQL query file
|
||||||
- `-dt` - fully qualified destination table name (migration mode only)
|
- `-dt` - fully qualified destination table name
|
||||||
- `-t` - trim text fields (default: true)
|
- `-t` - trim text fields (default: true)
|
||||||
- `-c` - clear target table before insert (default: true, migration mode only)
|
- `-c` - clear target table before insert (default: true)
|
||||||
- `-f` - output format: csv, tsv (query mode only, default: csv)
|
|
||||||
|
|
||||||
## Key Implementation Details
|
## Key Implementation Details
|
||||||
|
|
||||||
### Mode Detection
|
### Batch Size
|
||||||
Query mode is automatically detected at runtime (line 131) by checking if all destination flags (dcu, dcn, dcp, dt) are empty. This allows seamless switching between query and migration modes without explicit mode flags.
|
INSERT statements are batched at 250 rows (hardcoded at line 324). When the batch threshold is reached, sql is prepended with "INSERT INTO {table} VALUES" and executed.
|
||||||
|
|
||||||
### Query Mode Output (v1.1+)
|
|
||||||
Query mode uses dedicated output methods:
|
|
||||||
- `outputQueryResults()` - Dispatches to format-specific methods
|
|
||||||
- `outputCSV()` - RFC 4180 compliant CSV with proper quote escaping
|
|
||||||
- `outputTSV()` - Tab-separated with tabs/newlines replaced by spaces
|
|
||||||
- All output goes to stdout; no diagnostic messages in query mode
|
|
||||||
- Helper methods: `escapeCSV()` and `escapeTSV()` for proper formatting
|
|
||||||
|
|
||||||
### Batch Size (Migration Mode)
|
|
||||||
INSERT statements are batched at 250 rows (hardcoded around line 324). When the batch threshold is reached, sql is prepended with "INSERT INTO {table} VALUES" and executed.
|
|
||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
SQLException handling prints stack trace and exits immediately with System.exit(0). There is no transaction rollback or partial failure recovery.
|
SQLException handling prints stack trace and exits immediately with System.exit(0). There is no transaction rollback or partial failure recovery.
|
||||||
|
|
||||||
### Performance Considerations
|
### Performance Considerations
|
||||||
- Result set fetch size is set to 10,000 rows (line 190)
|
- Result set fetch size is set to 10,000 rows (line 173)
|
||||||
- Progress counter prints with carriage return for real-time updates (migration mode only)
|
- Progress counter prints with carriage return for real-time updates
|
||||||
- Timestamps captured at start and end for duration tracking (migration mode only)
|
- Timestamps captured at start (line 174) and end (line 368) for duration tracking
|
||||||
- Query mode has no progress output to keep stdout clean for piping
|
|
||||||
|
|||||||
93
deploy.sh
93
deploy.sh
@ -1,40 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "jrunner deployment script"
|
DEPLOY_DIR="${1:-/opt/jrunner}"
|
||||||
echo "========================="
|
|
||||||
echo ""
|
|
||||||
echo "Select deployment option:"
|
|
||||||
echo " 1) Local install (./jrunner/build/install)"
|
|
||||||
echo " 2) Global install (/opt/jrunner)"
|
|
||||||
echo " 3) Custom directory"
|
|
||||||
echo ""
|
|
||||||
read -p "Enter choice [1-3]: " choice
|
|
||||||
|
|
||||||
case $choice in
|
|
||||||
1)
|
|
||||||
DEPLOY_MODE="local"
|
|
||||||
DEPLOY_DIR="./jrunner/build/install/jrunner"
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
DEPLOY_MODE="global"
|
|
||||||
DEPLOY_DIR="/opt/jrunner"
|
|
||||||
;;
|
|
||||||
3)
|
|
||||||
DEPLOY_MODE="custom"
|
|
||||||
read -e -p "Enter deployment directory (required): " DEPLOY_DIR
|
|
||||||
if [ -z "$DEPLOY_DIR" ]; then
|
|
||||||
echo "Error: Directory path is required"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# Expand tilde to home directory
|
|
||||||
DEPLOY_DIR="${DEPLOY_DIR/#\~/$HOME}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Error: Invalid choice"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Prevent deleting critical system directories
|
# Prevent deleting critical system directories
|
||||||
case "${DEPLOY_DIR}" in
|
case "${DEPLOY_DIR}" in
|
||||||
@ -44,46 +11,32 @@ case "${DEPLOY_DIR}" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo ""
|
if [ ! -d "${DEPLOY_DIR}" ]; then
|
||||||
|
echo "Error: Directory does not exist: ${DEPLOY_DIR}"
|
||||||
|
echo "Create it first: sudo mkdir -p ${DEPLOY_DIR}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Building jrunner..."
|
echo "Building jrunner..."
|
||||||
./gradlew build
|
./gradlew build
|
||||||
|
|
||||||
if [ "$DEPLOY_MODE" = "local" ]; then
|
echo "Extracting to temporary location..."
|
||||||
echo "Installing locally with gradle..."
|
sudo rm -rf /tmp/jrunner
|
||||||
./gradlew installDist
|
sudo unzip -q jrunner/build/distributions/jrunner.zip -d /tmp/
|
||||||
echo ""
|
|
||||||
echo "✅ Installed locally at: ${DEPLOY_DIR}"
|
|
||||||
echo "Run './jrunner/build/install/jrunner/bin/jrunner --help' to test"
|
|
||||||
else
|
|
||||||
# Global or custom deployment
|
|
||||||
if [ ! -d "${DEPLOY_DIR}" ]; then
|
|
||||||
echo "Creating directory: ${DEPLOY_DIR}"
|
|
||||||
sudo mkdir -p "${DEPLOY_DIR}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Extracting to temporary location..."
|
echo "Deploying to ${DEPLOY_DIR}..."
|
||||||
sudo rm -rf /tmp/jrunner-deploy
|
sudo rm -rf "${DEPLOY_DIR}"/*
|
||||||
sudo unzip -q jrunner/build/distributions/jrunner.zip -d /tmp/jrunner-deploy
|
sudo mv /tmp/jrunner/* "${DEPLOY_DIR}"/
|
||||||
|
sudo rm -rf /tmp/jrunner
|
||||||
|
|
||||||
echo "Deploying to ${DEPLOY_DIR}..."
|
echo "Fixing ownership..."
|
||||||
sudo rm -rf "${DEPLOY_DIR}"/*
|
sudo chown -R $USER:$USER "${DEPLOY_DIR}"
|
||||||
sudo mv /tmp/jrunner-deploy/jrunner/* "${DEPLOY_DIR}"/
|
|
||||||
sudo rm -rf /tmp/jrunner-deploy
|
|
||||||
|
|
||||||
echo "Fixing ownership..."
|
# Only create symlink for /opt/jrunner
|
||||||
sudo chown -R $USER:$USER "${DEPLOY_DIR}"
|
if [ "${DEPLOY_DIR}" = "/opt/jrunner" ]; then
|
||||||
|
echo "Creating symlink..."
|
||||||
# Create symlink for global install
|
sudo ln -sf /opt/jrunner/bin/jrunner /usr/local/bin/jrunner
|
||||||
if [ "$DEPLOY_MODE" = "global" ]; then
|
|
||||||
echo "Creating symlink at /usr/local/bin/jrunner..."
|
|
||||||
sudo ln -sf /opt/jrunner/bin/jrunner /usr/local/bin/jrunner
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "✅ Deployed to ${DEPLOY_DIR}"
|
|
||||||
echo "Run '${DEPLOY_DIR}/bin/jrunner --help' to test"
|
|
||||||
|
|
||||||
if [ "$DEPLOY_MODE" = "global" ]; then
|
|
||||||
echo "Or simply: jrunner --help"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "✅ Deployed to ${DEPLOY_DIR}"
|
||||||
|
echo "Run '${DEPLOY_DIR}/bin/jrunner --help' to test"
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public class jrunner {
|
|||||||
Timestamp tsStart = null;
|
Timestamp tsStart = null;
|
||||||
Timestamp tsEnd = null;
|
Timestamp tsEnd = null;
|
||||||
|
|
||||||
msg = "jrunner version 1.1";
|
msg = "jrunner version 1.0";
|
||||||
msg = msg + nl + "-scu source jdbc url";
|
msg = msg + nl + "-scu source jdbc url";
|
||||||
msg = msg + nl + "-scn source username";
|
msg = msg + nl + "-scn source username";
|
||||||
msg = msg + nl + "-scp source passowrd";
|
msg = msg + nl + "-scp source passowrd";
|
||||||
@ -136,7 +136,12 @@ public class jrunner {
|
|||||||
// Detect query mode when destination flags are not provided
|
// Detect query mode when destination flags are not provided
|
||||||
queryMode = dcu.isEmpty() && dcn.isEmpty() && dcp.isEmpty() && dt.isEmpty();
|
queryMode = dcu.isEmpty() && dcn.isEmpty() && dcp.isEmpty() && dt.isEmpty();
|
||||||
|
|
||||||
if (!queryMode) {
|
if (queryMode) {
|
||||||
|
System.err.println("------------query mode------------------------------------");
|
||||||
|
System.err.println("source db uri: " + scu);
|
||||||
|
System.err.println("source db username: " + scn);
|
||||||
|
System.err.println("output format: " + outputFormat);
|
||||||
|
} else {
|
||||||
System.out.println("------------db info---------------------------------------");
|
System.out.println("------------db info---------------------------------------");
|
||||||
System.out.println("source db uri: " + scu);
|
System.out.println("source db uri: " + scu);
|
||||||
System.out.println("source db username: " + scn);
|
System.out.println("source db username: " + scn);
|
||||||
@ -160,7 +165,9 @@ public class jrunner {
|
|||||||
|
|
||||||
//-------------------------------------------establish connections-------------------------------------------------
|
//-------------------------------------------establish connections-------------------------------------------------
|
||||||
//source database
|
//source database
|
||||||
if (!queryMode) {
|
if (queryMode) {
|
||||||
|
System.err.println("------------open database connection---------------------");
|
||||||
|
} else {
|
||||||
System.out.println("------------open database connections---------------------");
|
System.out.println("------------open database connections---------------------");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -169,10 +176,8 @@ public class jrunner {
|
|||||||
System.out.println("issue connecting to source:");
|
System.out.println("issue connecting to source:");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
if (!queryMode) {
|
System.out.println(" ✅ source database");
|
||||||
System.out.println(" ✅ source database");
|
|
||||||
}
|
|
||||||
//destination database
|
//destination database
|
||||||
if (!queryMode) {
|
if (!queryMode) {
|
||||||
try {
|
try {
|
||||||
@ -189,9 +194,7 @@ public class jrunner {
|
|||||||
stmt = scon.createStatement();
|
stmt = scon.createStatement();
|
||||||
stmt.setFetchSize(10000);
|
stmt.setFetchSize(10000);
|
||||||
tsStart = Timestamp.from(Instant.now());
|
tsStart = Timestamp.from(Instant.now());
|
||||||
if (!queryMode) {
|
System.out.println(tsStart);
|
||||||
System.out.println(tsStart);
|
|
||||||
}
|
|
||||||
rs = stmt.executeQuery(sq);
|
rs = stmt.executeQuery(sq);
|
||||||
//while (rs.next()) {
|
//while (rs.next()) {
|
||||||
// System.out.println(rs.getString("x"));
|
// System.out.println(rs.getString("x"));
|
||||||
@ -205,10 +208,8 @@ public class jrunner {
|
|||||||
//---------------------------------------build meta---------------------------------------------------------------
|
//---------------------------------------build meta---------------------------------------------------------------
|
||||||
try {
|
try {
|
||||||
cols = rs.getMetaData().getColumnCount();
|
cols = rs.getMetaData().getColumnCount();
|
||||||
if (!queryMode) {
|
System.out.println("------------source metadata-------------------------------");
|
||||||
System.out.println("------------source metadata-------------------------------");
|
System.out.println("number of cols: " + cols);
|
||||||
System.out.println("number of cols: " + cols);
|
|
||||||
}
|
|
||||||
getv = new String[cols + 1];
|
getv = new String[cols + 1];
|
||||||
dtn = new String[cols + 1];
|
dtn = new String[cols + 1];
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@ -218,9 +219,7 @@ public class jrunner {
|
|||||||
try {
|
try {
|
||||||
for (int i = 1; i <= cols; i++){
|
for (int i = 1; i <= cols; i++){
|
||||||
dtn[i] = rs.getMetaData().getColumnTypeName(i);
|
dtn[i] = rs.getMetaData().getColumnTypeName(i);
|
||||||
if (!queryMode) {
|
System.out.println(" * " + rs.getMetaData().getColumnName(i) + ": " + dtn[i]);
|
||||||
System.out.println(" * " + rs.getMetaData().getColumnName(i) + ": " + dtn[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -419,8 +418,15 @@ public class jrunner {
|
|||||||
outputTSV(rs, cols);
|
outputTSV(rs, cols);
|
||||||
break;
|
break;
|
||||||
case "table":
|
case "table":
|
||||||
|
System.err.println("Table format not yet implemented, defaulting to CSV");
|
||||||
|
outputCSV(rs, cols);
|
||||||
|
break;
|
||||||
case "json":
|
case "json":
|
||||||
|
System.err.println("JSON format not yet implemented, defaulting to CSV");
|
||||||
|
outputCSV(rs, cols);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
System.err.println("Unknown format: " + format + ", defaulting to CSV");
|
||||||
outputCSV(rs, cols);
|
outputCSV(rs, cols);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
150
readme.md
150
readme.md
@ -1,52 +1,35 @@
|
|||||||
## Quick Start
|
## install java jdk.
|
||||||
|
find downloads page and get latest tarball.
|
||||||
|
https://www.oracle.com/java/technologies/downloads/
|
||||||
|
|
||||||
The easiest way to get started on a new system:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://gitea.hptrow.me/pt/jrunner.git
|
|
||||||
cd jrunner
|
|
||||||
./setup.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The setup script will:
|
|
||||||
- Check for Java 11+ (offers to install if missing)
|
|
||||||
- Verify Gradle wrapper is present
|
|
||||||
- Run a test build to ensure everything works
|
|
||||||
- Show you next steps
|
|
||||||
|
|
||||||
## Manual Installation
|
|
||||||
|
|
||||||
If you prefer to install dependencies manually:
|
|
||||||
|
|
||||||
### Install Java JDK
|
|
||||||
|
|
||||||
**Option 1: Package manager (recommended)**
|
|
||||||
```bash
|
|
||||||
# Ubuntu/Debian
|
|
||||||
sudo apt update && sudo apt install openjdk-17-jdk
|
|
||||||
|
|
||||||
# Fedora/RHEL
|
|
||||||
sudo dnf install java-17-openjdk-devel
|
|
||||||
|
|
||||||
# Arch
|
|
||||||
sudo pacman -S jdk-openjdk
|
|
||||||
```
|
|
||||||
|
|
||||||
**Option 2: Manual download**
|
|
||||||
Download from https://www.oracle.com/java/technologies/downloads/
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wget https://download.oracle.com/java/19/latest/jdk-19_linux-x64_bin.tar.gz
|
wget https://download.oracle.com/java/19/latest/jdk-19_linux-x64_bin.tar.gz
|
||||||
tar -xvf jdk-19_linux-x64_bin.tar.gz
|
tar -xvf downloaded_file
|
||||||
sudo mv jdk-19.0.1 /opt/
|
```
|
||||||
|
move the extracted folder to /opt
|
||||||
|
put the extracted location in your path variable
|
||||||
|
```
|
||||||
export JAVA_HOME=/opt/jdk-19.0.1
|
export JAVA_HOME=/opt/jdk-19.0.1
|
||||||
export PATH=$PATH:$JAVA_HOME/bin
|
export PATH=$PATH:$JAVA_HOME/bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Test: `java --version`
|
`java --version` to test
|
||||||
|
|
||||||
### Install Gradle (optional)
|
## install gradle (optional)
|
||||||
Gradle wrapper (`gradlew`) is included in the repo, so manual Gradle installation is not required.
|
Gradle wrapper (`gradlew`) is included in the repo, so manual Gradle installation is not required.
|
||||||
|
If you prefer to install Gradle system-wide:
|
||||||
|
```
|
||||||
|
wget https://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
|
unzip -d /opt/gradle gradle-8.5-bin.zip
|
||||||
|
export PATH=$PATH:/opt/gradle/gradle-8.5/bin
|
||||||
|
gradle -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## clone this repo
|
||||||
|
```
|
||||||
|
git clone https://gitea.hptrow.me/pt/jrunner.git
|
||||||
|
cd jrunner
|
||||||
|
```
|
||||||
|
|
||||||
## build
|
## build
|
||||||
```
|
```
|
||||||
@ -57,17 +40,22 @@ Gradle wrapper (`gradlew`) is included in the repo, so manual Gradle installatio
|
|||||||
|
|
||||||
### using the deploy script (recommended)
|
### using the deploy script (recommended)
|
||||||
|
|
||||||
Run the interactive deploy script:
|
First, create the deployment directory:
|
||||||
```
|
```
|
||||||
|
sudo mkdir -p /opt/jrunner
|
||||||
|
```
|
||||||
|
|
||||||
|
Then deploy:
|
||||||
|
```
|
||||||
|
# Deploy to /opt/jrunner (default, creates system-wide symlink)
|
||||||
./deploy.sh
|
./deploy.sh
|
||||||
|
|
||||||
|
# Deploy to custom location (for testing, no symlink)
|
||||||
|
sudo mkdir -p /opt/jrunner-test
|
||||||
|
./deploy.sh /opt/jrunner-test
|
||||||
```
|
```
|
||||||
|
|
||||||
The script will prompt you to choose:
|
The script builds, extracts to a temporary location, and only updates the target directory after the build succeeds. This ensures your existing deployment stays intact if the build fails. When deploying to `/opt/jrunner`, it creates a symlink at `/usr/local/bin/jrunner`.
|
||||||
1. **Local install** - Fast, no sudo required, installs to `./jrunner/build/install/jrunner`
|
|
||||||
2. **Global install** - Installs to `/opt/jrunner` with symlink at `/usr/local/bin/jrunner`
|
|
||||||
3. **Custom directory** - Prompts for path with tab-completion support
|
|
||||||
|
|
||||||
The script builds, extracts to a temporary location, and only updates the target directory after the build succeeds. This ensures your existing deployment stays intact if the build fails.
|
|
||||||
|
|
||||||
### manual deployment
|
### manual deployment
|
||||||
```
|
```
|
||||||
@ -76,72 +64,14 @@ sudo unzip jrunner/build/distributions/jrunner.zip -d /opt/
|
|||||||
sudo ln -sf /opt/jrunner/bin/jrunner /usr/local/bin/jrunner
|
sudo ln -sf /opt/jrunner/bin/jrunner /usr/local/bin/jrunner
|
||||||
```
|
```
|
||||||
|
|
||||||
Or for local testing:
|
|
||||||
```
|
|
||||||
./gradlew installDist
|
|
||||||
# Binary at: ./jrunner/build/install/jrunner/bin/jrunner
|
|
||||||
```
|
|
||||||
|
|
||||||
## usage
|
## usage
|
||||||
|
|
||||||
### Query Mode (new in v1.1)
|
After deployment to default location:
|
||||||
|
```
|
||||||
Query mode outputs results to stdout for piping to visidata, pspg, or less. It activates automatically when destination flags are omitted.
|
jrunner -scu jdbc:postgresql://... -scn user -scp pass ...
|
||||||
|
|
||||||
**Basic query to CSV:**
|
|
||||||
```bash
|
|
||||||
jrunner -scu "jdbc:as400://hostname" -scn user -scp pass -sq query.sql
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pipe to visidata:**
|
After deployment to custom location:
|
||||||
```bash
|
|
||||||
jrunner -scu "jdbc:as400://hostname" -scn user -scp pass -sq query.sql | visidata -f csv
|
|
||||||
```
|
```
|
||||||
|
/opt/jrunner-test/bin/jrunner -scu jdbc:postgresql://... -scn user -scp pass ...
|
||||||
**TSV format:**
|
|
||||||
```bash
|
|
||||||
jrunner -scu "jdbc:as400://hostname" -scn user -scp pass -sq query.sql -f tsv
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**SQL Server example:**
|
|
||||||
```bash
|
|
||||||
jrunner -scu "jdbc:sqlserver://hostname:1433;databaseName=mydb" -scn user -scp pass -sq query.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
**PostgreSQL example:**
|
|
||||||
```bash
|
|
||||||
jrunner -scu "jdbc:postgresql://hostname:5432/dbname" -scn user -scp pass -sq query.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
### Migration Mode
|
|
||||||
|
|
||||||
Full migration mode with both source and destination:
|
|
||||||
```bash
|
|
||||||
jrunner -scu jdbc:postgresql://source:5432/sourcedb \
|
|
||||||
-scn sourceuser \
|
|
||||||
-scp sourcepass \
|
|
||||||
-dcu jdbc:postgresql://dest:5432/destdb \
|
|
||||||
-dcn destuser \
|
|
||||||
-dcp destpass \
|
|
||||||
-sq query.sql \
|
|
||||||
-dt public.target_table
|
|
||||||
```
|
|
||||||
|
|
||||||
### Command-line flags
|
|
||||||
|
|
||||||
**Source connection:**
|
|
||||||
- `-scu` - source JDBC URL
|
|
||||||
- `-scn` - source username
|
|
||||||
- `-scp` - source password
|
|
||||||
- `-sq` - path to source SQL query file
|
|
||||||
|
|
||||||
**Destination connection (migration mode only):**
|
|
||||||
- `-dcu` - destination JDBC URL
|
|
||||||
- `-dcn` - destination username
|
|
||||||
- `-dcp` - destination password
|
|
||||||
- `-dt` - fully qualified destination table name
|
|
||||||
|
|
||||||
**Options:**
|
|
||||||
- `-t` - trim text fields (default: true)
|
|
||||||
- `-c` - clear target table before insert (default: true)
|
|
||||||
- `-f` - output format: csv, tsv (query mode only, default: csv)
|
|
||||||
|
|||||||
174
setup.sh
174
setup.sh
@ -1,174 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "jrunner Development Environment Setup"
|
|
||||||
echo "====================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Color codes for output
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# Check if running on Linux
|
|
||||||
if [[ "$OSTYPE" != "linux-gnu"* ]]; then
|
|
||||||
echo -e "${YELLOW}Warning: This script is designed for Linux. You may need to manually install dependencies.${NC}"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Function to check if command exists
|
|
||||||
command_exists() {
|
|
||||||
command -v "$1" >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to get Java version
|
|
||||||
get_java_version() {
|
|
||||||
if command_exists java; then
|
|
||||||
java -version 2>&1 | head -n 1 | awk -F '"' '{print $2}' | awk -F '.' '{print $1}'
|
|
||||||
else
|
|
||||||
echo "0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "Checking dependencies..."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Check Java
|
|
||||||
JAVA_VERSION=$(get_java_version)
|
|
||||||
if [ "$JAVA_VERSION" -ge 11 ]; then
|
|
||||||
echo -e "${GREEN}✓${NC} Java $JAVA_VERSION detected"
|
|
||||||
java -version 2>&1 | head -n 1
|
|
||||||
JAVA_OK=true
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗${NC} Java 11+ not found"
|
|
||||||
JAVA_OK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check Git
|
|
||||||
if command_exists git; then
|
|
||||||
echo -e "${GREEN}✓${NC} Git detected"
|
|
||||||
DEPENDENCIES_OK=true
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗${NC} Git not found"
|
|
||||||
DEPENDENCIES_OK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if gradlew exists
|
|
||||||
if [ -f "./gradlew" ]; then
|
|
||||||
echo -e "${GREEN}✓${NC} Gradle wrapper found (no need to install Gradle)"
|
|
||||||
GRADLE_OK=true
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}!${NC} Gradle wrapper not found in current directory"
|
|
||||||
GRADLE_OK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# If Java is missing, offer installation help
|
|
||||||
if [ "$JAVA_OK" = false ]; then
|
|
||||||
echo -e "${YELLOW}Java 11+ is required to build and run jrunner${NC}"
|
|
||||||
echo ""
|
|
||||||
echo "Installation options:"
|
|
||||||
echo ""
|
|
||||||
echo "1. Install OpenJDK via package manager (recommended):"
|
|
||||||
echo " Ubuntu/Debian: sudo apt update && sudo apt install openjdk-17-jdk"
|
|
||||||
echo " Fedora/RHEL: sudo dnf install java-17-openjdk-devel"
|
|
||||||
echo " Arch: sudo pacman -S jdk-openjdk"
|
|
||||||
echo ""
|
|
||||||
echo "2. Download Oracle JDK manually:"
|
|
||||||
echo " Visit: https://www.oracle.com/java/technologies/downloads/"
|
|
||||||
echo " Download JDK 17+ tarball and extract to /opt"
|
|
||||||
echo " Add to PATH: export JAVA_HOME=/opt/jdk-17 && export PATH=\$PATH:\$JAVA_HOME/bin"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
read -p "Would you like to install OpenJDK via package manager? (requires sudo) [y/N]: " install_java
|
|
||||||
|
|
||||||
if [[ "$install_java" =~ ^[Yy]$ ]]; then
|
|
||||||
if command_exists apt; then
|
|
||||||
echo "Installing OpenJDK 17 via apt..."
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y openjdk-17-jdk
|
|
||||||
elif command_exists dnf; then
|
|
||||||
echo "Installing OpenJDK 17 via dnf..."
|
|
||||||
sudo dnf install -y java-17-openjdk-devel
|
|
||||||
elif command_exists pacman; then
|
|
||||||
echo "Installing OpenJDK via pacman..."
|
|
||||||
sudo pacman -S --noconfirm jdk-openjdk
|
|
||||||
else
|
|
||||||
echo -e "${RED}Could not detect package manager. Please install Java manually.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify installation
|
|
||||||
JAVA_VERSION=$(get_java_version)
|
|
||||||
if [ "$JAVA_VERSION" -ge 11 ]; then
|
|
||||||
echo -e "${GREEN}✓ Java installed successfully${NC}"
|
|
||||||
JAVA_OK=true
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Java installation failed${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo "Please install Java manually and re-run this script."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for unzip (needed for deployment)
|
|
||||||
if ! command_exists unzip; then
|
|
||||||
echo -e "${YELLOW}Note: 'unzip' is recommended for deployment${NC}"
|
|
||||||
read -p "Install unzip? [y/N]: " install_unzip
|
|
||||||
if [[ "$install_unzip" =~ ^[Yy]$ ]]; then
|
|
||||||
if command_exists apt; then
|
|
||||||
sudo apt install -y unzip
|
|
||||||
elif command_exists dnf; then
|
|
||||||
sudo dnf install -y unzip
|
|
||||||
elif command_exists pacman; then
|
|
||||||
sudo pacman -S --noconfirm unzip
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}All required dependencies are installed!${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Verify we're in the right directory
|
|
||||||
if [ ! -f "./gradlew" ]; then
|
|
||||||
echo -e "${RED}Error: gradlew not found. Are you in the jrunner project directory?${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make gradlew executable
|
|
||||||
chmod +x ./gradlew
|
|
||||||
|
|
||||||
echo "Testing build system..."
|
|
||||||
if ./gradlew --version > /dev/null 2>&1; then
|
|
||||||
echo -e "${GREEN}✓${NC} Gradle wrapper working"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗${NC} Gradle wrapper failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Running test build..."
|
|
||||||
if ./gradlew build; then
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}✓ Build successful!${NC}"
|
|
||||||
echo ""
|
|
||||||
echo "Next steps:"
|
|
||||||
echo " 1. Install locally for testing:"
|
|
||||||
echo " ./gradlew installDist"
|
|
||||||
echo " ./jrunner/build/install/jrunner/bin/jrunner --help"
|
|
||||||
echo ""
|
|
||||||
echo " 2. Or run the interactive deploy script:"
|
|
||||||
echo " ./deploy.sh"
|
|
||||||
echo ""
|
|
||||||
echo " 3. See readme.md for usage examples"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Build failed${NC}"
|
|
||||||
echo "Check the error messages above and try again."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Loading…
Reference in New Issue
Block a user