1
- use jwalk:: WalkDir ;
2
1
use liboxen:: api;
3
2
use liboxen:: command;
3
+ use liboxen:: command:: migrate:: CreateMerkleTreesMigration ;
4
+ use liboxen:: command:: migrate:: Migrate ;
5
+ use liboxen:: command:: migrate:: UpdateVersionFilesMigration ;
4
6
use liboxen:: config:: { AuthConfig , UserConfig } ;
5
7
use liboxen:: constants;
6
8
use liboxen:: error;
@@ -22,6 +24,7 @@ use liboxen::opts::PaginateOpts;
22
24
use liboxen:: opts:: RestoreOpts ;
23
25
use liboxen:: opts:: RmOpts ;
24
26
use liboxen:: util;
27
+ use liboxen:: util:: oxen_version:: OxenVersion ;
25
28
26
29
use colored:: Colorize ;
27
30
use liboxen:: view:: PaginatedDirEntries ;
@@ -66,51 +69,62 @@ pub async fn check_remote_version(host: impl AsRef<str>) -> Result<(), OxenError
66
69
eprintln ! ( "Err checking remote version: {err}" )
67
70
}
68
71
}
69
-
70
72
Ok ( ( ) )
71
73
}
72
74
73
- fn version_files_out_of_date ( repo : & LocalRepository ) -> Result < bool , OxenError > {
74
- let versions_dir = repo
75
- . path
76
- . join ( constants:: OXEN_HIDDEN_DIR )
77
- . join ( constants:: VERSIONS_DIR ) ;
78
- if !versions_dir. exists ( ) {
79
- return Ok ( false ) ;
80
- }
81
- for entry in WalkDir :: new ( & versions_dir) {
82
- let entry = entry?;
83
- if entry. file_type ( ) . is_file ( ) {
84
- let path = entry. path ( ) ;
85
- let filename = match path. file_name ( ) {
86
- Some ( filename) => filename. to_string_lossy ( ) . to_string ( ) ,
87
- None => continue ,
88
- } ;
89
-
90
- if filename. starts_with ( constants:: HASH_FILE ) {
91
- continue ;
92
- }
93
-
94
- if filename. starts_with ( constants:: VERSION_FILE_NAME ) {
95
- return Ok ( false ) ;
75
+ pub async fn check_remote_version_blocking ( host : impl AsRef < str > ) -> Result < ( ) , OxenError > {
76
+ match api:: remote:: version:: get_min_cli_version ( host. as_ref ( ) ) . await {
77
+ Ok ( remote_version) => {
78
+ let local_version: & str = constants:: OXEN_VERSION ;
79
+ let min_oxen_version = OxenVersion :: from_str ( & remote_version) ?;
80
+ let local_oxen_version = OxenVersion :: from_str ( local_version) ?;
81
+
82
+ if local_oxen_version < min_oxen_version {
83
+ return Err ( OxenError :: OxenUpdateRequired ( format ! (
84
+ "Error: Oxen CLI out of date. Pushing to OxenHub requires version >= {:?}, found version {:?}.\n \n Visit https://docs.oxen.ai/getting-started/intro for update instructions." ,
85
+ min_oxen_version,
86
+ local_oxen_version
87
+ ) . into ( ) ) ) ;
96
88
}
97
- return Ok ( true ) ;
89
+ }
90
+ Err ( _) => {
91
+ return Err ( OxenError :: basic_str (
92
+ "Error: unable to verify remote version" ,
93
+ ) ) ;
98
94
}
99
95
}
100
- Ok ( false )
96
+ Ok ( ( ) )
101
97
}
102
98
103
- pub fn check_versions_migration_needed ( repo : & LocalRepository ) -> Result < ( ) , OxenError > {
104
- let migration_needed = version_files_out_of_date ( repo) ?;
99
+ pub fn check_repo_migration_needed ( repo : & LocalRepository ) -> Result < ( ) , OxenError > {
100
+ let migrations: Vec < Box < dyn Migrate > > = vec ! [
101
+ Box :: new( UpdateVersionFilesMigration ) ,
102
+ Box :: new( CreateMerkleTreesMigration ) ,
103
+ ] ;
104
+
105
+ let mut migrations_needed: Vec < Box < dyn Migrate > > = Vec :: new ( ) ;
105
106
106
- if migration_needed {
107
- let warning = "Warning: 🐂 This repo requires a quick migration to the latest Oxen version.\n \n Please run `oxen migrate up update-version-files .` to migrate.\n " . to_string ( ) . yellow ( ) ;
108
- eprintln ! ( "{warning}" ) ;
109
- return Err ( OxenError :: MigrationRequired (
110
- "Error: Migration required" . to_string ( ) . into ( ) ,
111
- ) ) ;
107
+ for migration in migrations {
108
+ if migration. is_needed ( repo) ? {
109
+ migrations_needed. push ( migration) ;
110
+ }
112
111
}
113
- Ok ( ( ) )
112
+
113
+ if migrations_needed. is_empty ( ) {
114
+ return Ok ( ( ) ) ;
115
+ }
116
+ let warning = "\n Warning: 🐂 This repo requires a quick migration to the latest Oxen version. \n \n Please run the following to update:" . to_string ( ) . yellow ( ) ;
117
+ eprintln ! ( "{warning}\n \n " ) ;
118
+ for migration in migrations_needed {
119
+ eprintln ! (
120
+ "{}" ,
121
+ format!( "oxen migrate up {} .\n " , migration. name( ) ) . yellow( )
122
+ ) ;
123
+ }
124
+ eprintln ! ( "\n " ) ;
125
+ Err ( OxenError :: MigrationRequired (
126
+ "Error: Migration required" . to_string ( ) . into ( ) ,
127
+ ) )
114
128
}
115
129
116
130
pub async fn init ( path : & str ) -> Result < ( ) , OxenError > {
@@ -126,6 +140,7 @@ pub async fn init(path: &str) -> Result<(), OxenError> {
126
140
127
141
pub async fn clone ( opts : & CloneOpts ) -> Result < ( ) , OxenError > {
128
142
let host = api:: remote:: client:: get_host_from_url ( & opts. url ) ?;
143
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
129
144
check_remote_version ( host) . await ?;
130
145
131
146
command:: clone ( opts) . await ?;
@@ -304,6 +319,8 @@ pub async fn download(opts: DownloadOpts) -> Result<(), OxenError> {
304
319
return Err ( OxenError :: basic_str ( "Must supply a path to download." ) ) ;
305
320
}
306
321
322
+ check_remote_version_blocking ( opts. clone ( ) . host ) . await ?;
323
+
307
324
// Check if the first path is a valid remote repo
308
325
let name = paths[ 0 ] . to_string_lossy ( ) ;
309
326
if let Some ( remote_repo) =
@@ -329,6 +346,7 @@ pub async fn remote_download(opts: DownloadOpts) -> Result<(), OxenError> {
329
346
return Err ( OxenError :: basic_str ( "Must supply a path to download." ) ) ;
330
347
}
331
348
349
+ check_remote_version_blocking ( opts. clone ( ) . host ) . await ?;
332
350
// Check if the first path is a valid remote repo
333
351
let name = paths[ 0 ] . to_string_lossy ( ) ;
334
352
if let Some ( remote_repo) =
@@ -414,6 +432,7 @@ pub async fn remote_metadata_list_image(path: impl AsRef<Path>) -> Result<(), Ox
414
432
pub async fn add ( opts : AddOpts ) -> Result < ( ) , OxenError > {
415
433
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
416
434
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
435
+ check_repo_migration_needed ( & repository) ?;
417
436
418
437
for path in & opts. paths {
419
438
if opts. is_remote {
@@ -429,6 +448,7 @@ pub async fn add(opts: AddOpts) -> Result<(), OxenError> {
429
448
pub async fn rm ( paths : Vec < PathBuf > , opts : & RmOpts ) -> Result < ( ) , OxenError > {
430
449
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
431
450
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
451
+ check_repo_migration_needed ( & repository) ?;
432
452
433
453
for path in paths {
434
454
let path_opts = RmOpts :: from_path_opts ( & path, opts) ;
@@ -442,7 +462,7 @@ pub async fn restore(opts: RestoreOpts) -> Result<(), OxenError> {
442
462
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
443
463
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
444
464
445
- check_versions_migration_needed ( & repository) ?;
465
+ check_repo_migration_needed ( & repository) ?;
446
466
if opts. is_remote {
447
467
command:: remote:: restore ( & repository, opts) . await ?;
448
468
} else {
@@ -455,9 +475,10 @@ pub async fn restore(opts: RestoreOpts) -> Result<(), OxenError> {
455
475
pub async fn push ( remote : & str , branch : & str ) -> Result < ( ) , OxenError > {
456
476
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
457
477
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
458
-
459
- check_versions_migration_needed ( & repository) ?;
460
478
let host = get_host_from_repo ( & repository) ?;
479
+
480
+ check_repo_migration_needed ( & repository) ?;
481
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
461
482
check_remote_version ( host) . await ?;
462
483
463
484
command:: push_remote_branch ( & repository, remote, branch) . await ?;
@@ -469,7 +490,8 @@ pub async fn pull(remote: &str, branch: &str, all: bool) -> Result<(), OxenError
469
490
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
470
491
471
492
let host = get_host_from_repo ( & repository) ?;
472
- check_versions_migration_needed ( & repository) ?;
493
+ check_repo_migration_needed ( & repository) ?;
494
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
473
495
check_remote_version ( host) . await ?;
474
496
475
497
command:: pull_remote_branch ( & repository, remote, branch, all) . await ?;
@@ -501,6 +523,7 @@ pub fn compare(
501
523
) -> Result < ( ) , OxenError > {
502
524
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
503
525
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
526
+ check_repo_migration_needed ( & repository) ?;
504
527
505
528
let current_commit = api:: local:: commits:: head_commit ( & repository) ?;
506
529
// For revision_1 and revision_2, if none, set to current_commit
@@ -528,6 +551,7 @@ pub fn compare(
528
551
pub fn merge ( branch : & str ) -> Result < ( ) , OxenError > {
529
552
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
530
553
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
554
+ check_repo_migration_needed ( & repository) ?;
531
555
532
556
command:: merge ( & repository, branch) ?;
533
557
Ok ( ( ) )
@@ -536,6 +560,7 @@ pub fn merge(branch: &str) -> Result<(), OxenError> {
536
560
pub async fn commit ( message : & str , is_remote : bool ) -> Result < ( ) , OxenError > {
537
561
let repo_dir = env:: current_dir ( ) . unwrap ( ) ;
538
562
let repo = LocalRepository :: from_dir ( & repo_dir) ?;
563
+ check_repo_migration_needed ( & repo) ?;
539
564
540
565
if is_remote {
541
566
println ! ( "Committing to remote with message: {message}" ) ;
@@ -562,6 +587,10 @@ pub async fn fetch() -> Result<(), OxenError> {
562
587
util:: fs:: get_repo_root ( & current_dir) . ok_or ( OxenError :: basic_str ( error:: NO_REPO_FOUND ) ) ?;
563
588
564
589
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
590
+ let host = get_host_from_repo ( & repository) ?;
591
+
592
+ check_repo_migration_needed ( & repository) ?;
593
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
565
594
command:: fetch ( & repository) . await ?;
566
595
Ok ( ( ) )
567
596
}
@@ -615,6 +644,8 @@ pub async fn status(directory: Option<PathBuf>, opts: &StagedDataOpts) -> Result
615
644
616
645
let directory = directory. unwrap_or ( current_dir) ;
617
646
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
647
+ check_repo_migration_needed ( & repository) ?;
648
+
618
649
let repo_status = command:: status_from_dir ( & repository, & directory) ?;
619
650
620
651
if let Some ( current_branch) = api:: local:: branches:: current_branch ( & repository) ? {
@@ -681,6 +712,7 @@ async fn remote_status(directory: Option<PathBuf>, opts: &StagedDataOpts) -> Res
681
712
682
713
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
683
714
let host = get_host_from_repo ( & repository) ?;
715
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
684
716
check_remote_version ( host) . await ?;
685
717
686
718
let directory = directory. unwrap_or ( PathBuf :: from ( "." ) ) ;
@@ -746,6 +778,7 @@ pub async fn remote_ls(opts: &ListOpts) -> Result<(), OxenError> {
746
778
let repository = LocalRepository :: from_dir ( & repo_dir) ?;
747
779
748
780
let host = get_host_from_repo ( & repository) ?;
781
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
749
782
check_remote_version ( host) . await ?;
750
783
751
784
let directory = paths[ 0 ] . clone ( ) ;
@@ -1032,6 +1065,7 @@ pub async fn list_remote_branches(name: &str) -> Result<(), OxenError> {
1032
1065
let repo = LocalRepository :: from_dir ( & repo_dir) ?;
1033
1066
1034
1067
let host = get_host_from_repo ( & repo) ?;
1068
+ check_remote_version_blocking ( host. clone ( ) ) . await ?;
1035
1069
check_remote_version ( host) . await ?;
1036
1070
1037
1071
let remote = repo
0 commit comments