Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ helix-cli/
- `helix add` - Add dependencies to project
- `helix auth` - Authentication management (login/logout/create-key)
- `helix build` - Build queries without deploying
- `helix branch` - Branch a local instance database
- `helix check` - Validate schema and query syntax
- `helix compile` - Compile queries to Rust code
- `helix delete` - Remove instance and data
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions helix-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ indicatif = "0.18.3"
webbrowser = "1.0"
heed3 = "0.22.0"
open = "5.3"
fs2 = "0.4.3"

[dev-dependencies]
tempfile = "3.23.0"
Expand Down
5 changes: 5 additions & 0 deletions helix-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ push
- (--force/--f)
pull
- (<cluster_id|alias>)
branch
- (<instance>)
- (--output/--o)
- (--name)
- (--port)
init
- (--template/--t): template to use e.g. ts, py, fli.io, docker etc.
- (--alias/--a): name to call cluster
Expand Down
1 change: 1 addition & 0 deletions helix-cli/src/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ async fn run_add_inner(
let local_config = LocalInstanceConfig {
port: None, // Let the system assign a port
build_mode: BuildMode::Debug,
data_dir: None,
db_config: DbConfig::default(),
};

Expand Down
79 changes: 45 additions & 34 deletions helix-cli/src/commands/backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,50 @@ pub async fn run(output: Option<PathBuf>, instance_name: String) -> Result<()> {
// Load project context
let project = ProjectContext::find_and_load(None)?;

// Get instance config
let _instance_config = project.config.get_instance(&instance_name)?;

print_status("BACKUP", &format!("Backing up instance '{instance_name}'"));

// Get the instance volume
let volumes_dir = project
.root
.join(".helix")
.join(".volumes")
.join(&instance_name)
.join("user");
// Get path to backup instance
let backup_dir = match output {
Some(path) => path,
None => {
let ts = chrono::Local::now()
.format("backup-%Y%m%d-%H%M%S")
.to_string();
project.root.join("backups").join(ts)
}
};

let completed = backup_instance_to_dir(&project, &instance_name, &backup_dir)?;
if !completed {
return Ok(());
}

print_success(&format!(
"Backup for '{instance_name}' created at {:?}",
backup_dir
));

let data_file = volumes_dir.join("data.mdb");
Ok(())
}

let env_path = Path::new(&volumes_dir);
pub(crate) fn backup_instance_to_dir(
project: &ProjectContext,
instance_name: &str,
output_dir: &Path,
) -> Result<bool> {
// Get instance config
let instance_config = project.config.get_instance(instance_name)?;

if !instance_config.is_local() {
return Err(eyre::eyre!(
"Backup is only supported for local instances"
));
}

// Get the instance volume
let env_path = project.instance_user_dir(instance_name)?;
let data_file = project.instance_data_file(instance_name)?;
let env_path = Path::new(&env_path);

// Validate existence of environment
if !env_path.exists() {
Expand All @@ -44,26 +72,14 @@ pub async fn run(output: Option<PathBuf>, instance_name: String) -> Result<()> {
));
}

// Get path to backup instance
let backup_dir = match output {
Some(path) => path,
None => {
let ts = chrono::Local::now()
.format("backup-%Y%m%d-%H%M%S")
.to_string();
project.root.join("backups").join(ts)
}
};

create_dir_all(&backup_dir)?;
create_dir_all(output_dir)?;

// Get the size of the data
let total_size = fs::metadata(&data_file)?.len();

const TEN_GB: u64 = 10 * 1024 * 1024 * 1024;

// Check and warn if file is greater than 10 GB

if total_size > TEN_GB {
let size_gb = (total_size as f64) / (1024.0 * 1024.0 * 1024.0);
print_warning(&format!(
Expand All @@ -73,7 +89,7 @@ pub async fn run(output: Option<PathBuf>, instance_name: String) -> Result<()> {
let confirmed = print_confirm("Do you want to continue?");
if !confirmed? {
print_status("CANCEL", "Backup aborted by user");
return Ok(());
return Ok(false);
}
}

Expand All @@ -86,15 +102,10 @@ pub async fn run(output: Option<PathBuf>, instance_name: String) -> Result<()> {
.open(env_path)?
};

println!("Copying {:?} → {:?}", &data_file, &backup_dir);
println!("Copying {:?} → {:?}", &data_file, &output_dir);

// backup database to given database
env.copy_to_path(backup_dir.join("data.mdb"), CompactionOption::Disabled)?;
env.copy_to_path(output_dir.join("data.mdb"), CompactionOption::Disabled)?;

print_success(&format!(
"Backup for '{instance_name}' created at {:?}",
backup_dir
));

Ok(())
Ok(true)
}
Loading