1- import { Command , Flags } from '@oclif/core'
1+ import { Command , Flags } from '@oclif/core'
2+ import fs from 'fs-extra'
3+ import inquirer from 'inquirer'
4+ import path from 'path'
25import { ImapService } from '../services/imap/sync.service.js'
36
47export default class Sync extends Command {
@@ -8,14 +11,13 @@ export default class Sync extends Command {
811 '<%= config.bin %> <%= command.id %>' ,
912 '<%= config.bin %> <%= command.id %> --csv input/my-migration.csv' ,
1013 '<%= config.bin %> <%= command.id %> --dry-run --jobs 4' ,
11- '<%= config.bin %> <%= command.id %> --docker --log-dir ./logs /sync' ,
14+ '<%= config.bin %> <%= command.id %> --docker --log-dir ./results /sync-log ' ,
1215 ]
1316
1417 static flags = {
1518 csv : Flags . string ( {
1619 char : 'c' ,
17- description : 'CSV file containing sync configurations' ,
18- default : 'input/example.csv' ,
20+ description : 'CSV file containing sync configurations (will prompt if not provided)' ,
1921 } ) ,
2022 jobs : Flags . string ( {
2123 char : 'j' ,
@@ -27,22 +29,130 @@ export default class Sync extends Command {
2729 } ) ,
2830 'log-dir' : Flags . string ( {
2931 description : 'Log directory' ,
30- default : './results' ,
32+ default : './results/sync-log ' ,
3133 } ) ,
3234 'dry-run' : Flags . boolean ( {
3335 description : 'Show what would be synced without actually syncing' ,
3436 } ) ,
3537 }
3638
39+ async promptForCsvFile ( ) {
40+ // Get available CSV files from input/sync directory
41+ const syncDir = path . join ( process . cwd ( ) , 'input' , 'sync' )
42+ const inputDir = path . join ( process . cwd ( ) , 'input' )
43+ const choices = [ ]
44+
45+ try {
46+ // Add files from input/sync/ directory
47+ if ( await fs . pathExists ( syncDir ) ) {
48+ const syncFiles = await fs . readdir ( syncDir )
49+ const csvFiles = syncFiles . filter ( file => file . endsWith ( '.csv' ) )
50+ csvFiles . forEach ( file => {
51+ choices . push ( {
52+ name : `input/sync/${ file } ` ,
53+ value : `input/sync/${ file } ` ,
54+ short : file
55+ } )
56+ } )
57+ }
58+
59+ // Add some files from input/ directory that are sync-related
60+ if ( await fs . pathExists ( inputDir ) ) {
61+ const inputFiles = await fs . readdir ( inputDir )
62+ const syncRelatedFiles = inputFiles . filter ( file =>
63+ file . endsWith ( '.csv' ) &&
64+ ( file . includes ( 'sync' ) || file . includes ( 'imap' ) )
65+ )
66+ syncRelatedFiles . forEach ( file => {
67+ choices . push ( {
68+ name : `input/${ file } ` ,
69+ value : `input/${ file } ` ,
70+ short : file
71+ } )
72+ } )
73+ }
74+
75+ // Add option to specify custom path
76+ choices . push ( {
77+ name : 'Enter custom file path' ,
78+ value : 'custom' ,
79+ short : 'custom'
80+ } )
81+
82+ if ( choices . length === 1 ) {
83+ // Only custom option available
84+ const { customPath } = await inquirer . prompt ( [
85+ {
86+ type : 'input' ,
87+ name : 'customPath' ,
88+ message : 'Enter CSV file path:' ,
89+ default : 'input/sync/example.csv' ,
90+ validate : input => input . trim ( ) . length > 0 ? true : 'Please enter a file path'
91+ }
92+ ] )
93+ return customPath
94+ }
95+
96+ const { selectedFile } = await inquirer . prompt ( [
97+ {
98+ type : 'list' ,
99+ name : 'selectedFile' ,
100+ message : 'Select CSV file for sync configuration:' ,
101+ choices : choices ,
102+ pageSize : 10
103+ }
104+ ] )
105+
106+ if ( selectedFile === 'custom' ) {
107+ const { customPath } = await inquirer . prompt ( [
108+ {
109+ type : 'input' ,
110+ name : 'customPath' ,
111+ message : 'Enter CSV file path:' ,
112+ default : 'input/sync/example.csv' ,
113+ validate : input => input . trim ( ) . length > 0 ? true : 'Please enter a file path'
114+ }
115+ ] )
116+ return customPath
117+ }
118+
119+ return selectedFile
120+ } catch ( error ) {
121+ this . log ( 'Error reading input directories, please enter file path manually:' )
122+ const { customPath } = await inquirer . prompt ( [
123+ {
124+ type : 'input' ,
125+ name : 'customPath' ,
126+ message : 'Enter CSV file path:' ,
127+ default : 'input/sync/example.csv' ,
128+ validate : input => input . trim ( ) . length > 0 ? true : 'Please enter a file path'
129+ }
130+ ] )
131+ return customPath
132+ }
133+ }
134+
37135 async run ( ) {
38136 const { flags} = await this . parse ( Sync )
39137
40138 try {
139+ // If CSV flag is not provided, prompt user for CSV file
140+ let csvFile = flags . csv
141+ if ( ! csvFile ) {
142+ this . log ( 'No CSV file specified, please select one:' )
143+ csvFile = await this . promptForCsvFile ( )
144+ }
145+
146+ // Validate that the file exists
147+ if ( ! await fs . pathExists ( csvFile ) ) {
148+ this . error ( `CSV file not found: ${ csvFile } ` )
149+ }
150+
41151 const imapService = new ImapService ( )
42152
43153 // Map flags to options format expected by the service
44154 const options = {
45- csv : flags . csv ,
155+ csv : csvFile ,
46156 jobs : flags . jobs ,
47157 docker : flags . docker ,
48158 logDir : flags [ 'log-dir' ] ,
0 commit comments