diff --git a/README.md b/README.md index 93345d2..34ba4e3 100644 --- a/README.md +++ b/README.md @@ -70,24 +70,26 @@ tbd ## configuration -your SHARE repo (in 1 single place, i.e. storage media on your NAS) needs to provide a `.syncshare.json`file with ... TODO -// NEXT +The “topology” here is very simply a „star“ with 1 central SHARE repo (in which you may indeed work, too!) and an arbitrary number of LOCAL repos. Where that “arbitrary” number might very well be 1, if you happen to have one desktop for home (as SHARE) and 1 laptop on the go. It's easy to later on add additional members. + +your SHARE repo (in 1 single place, i.e. storage media on your NAS) needs to provide a `.syncshare.json`file with global settings relating to your entire system + +→ if you are happy with [the default settings](./defaultConfig.json), e.g. for `excludedExtensions`, `MAX_FILE_SIZE_MB`, it's sheer presence is enough (with or without empty curly brackets inside). Then it's just a marker file. ```json { - + "excludedExtensions": [... , + "MAX_FILE_SIZE_MB": 30, } ``` -if not overriden, regarding `excludedExtensions`, `MAX_FILE_SIZE_MB` [these defaults](./defaultConfig.json) will “rule”... - - -your LOCAL repo (on every one of your machines) needs to provide a `.synclocal.json`file with EXACTLY these 2 entries: +your LOCAL repo (on every one of your machines) however does need to provide a `.synclocal.json` file with EXACTLY these 2 entries: ```json { - machineName: os.hostname(), // what uname -n delivers, just a safety measure - shareRepo: SHARE // the share repo to connect to + machineName: os.hostname(), // what uname -n delivers, localRepo: '/home/user/' + localRepo: 'mySyncDocsFolder', // again, ensuring the right place + shareRepo: '/fritzbox/usb-stick/SHARE' // the share repo to connect to } ``` diff --git a/src/getConfig.js b/src/getConfig.js index 4f17d5e..45ca145 100644 --- a/src/getConfig.js +++ b/src/getConfig.js @@ -16,7 +16,7 @@ function loadJsonC(path) { try { const jsoncfile = fs.readFileSync(path, 'utf8') const withoutComments = jsoncfile.replace(/(?<=(^|[^"]*"[^"]*")*[^"]*)\/\/.*$/gm, '') - const withoutTrailingCommas = withoutComments.replace(/,\s*([\]}])/g, '$1'); // Remove trailing commas + const withoutTrailingCommas = withoutComments.replace(/,\s*([\]}])/g, '$1') // Remove trailing commas return JSON.parse(withoutTrailingCommas) } catch (error) { fail(`failed on loading/parsing JSON/JSONC-File '${path}': ${error.message}`) @@ -53,27 +53,45 @@ const getConfig = (cwd) => { info(`Test Mode: ${testMode}`) // check if there is a .syncdocs.json in the CURRENT dir - const syncdocsJsonPath = '.syncdocs.json' - const hasSyncdocsJson = fs.existsSync(syncdocsJsonPath) - if (!hasSyncdocsJson) { + const localJsonPath = '.synclocal.json' + if (!fs.existsSync(localJsonPath)) { fail(`No .syncdocs.json found in current directory ${cwd} — not a syncdocs folder?`) } ensureFolderExists('.git',`No .git folder in current directory ${cwd}, only a .syncdocs.json — trouble?`) const defaultJson = loadJsonC(path.join(PROJECTROOT, 'defaultConfig.json')) - const projectJson = loadJsonC(syncdocsJsonPath) + const localJson = loadJsonC(localJsonPath) - const mustBeInProjectJson = ['machineName', 'localRepo', 'shareRepo'] - mustBeInProjectJson.forEach((prop) => { + const mandatoryLocalKeys = ['machineName', 'localRepo', 'shareRepo'] + + ensureTrue(Object.keys(localJson).length ==mandatoryLocalKeys.length, + `local '.syncdocs.json' must have exactly ${mandatoryLocalKeys.length} keys: ${mandatoryLocalKeys.join(', ')}`) + + mandatoryLocalKeys.forEach((prop) => { ensureTrue( defaultJson[prop] === undefined, `key: ${prop} must not be in defaultJson`) - ensureTruthy( projectJson[prop] && projectJson[prop].length > 0, `key: ${prop} must be in .syncdocs.json`) + ensureTruthy( localJson[prop] && localJson[prop].length > 0, `key: ${prop} must be in .syncdocs.json`) + }) + + ensureFolderExists(localJson.shareRepo, `folder given as 'shareRepo' '${localJson.shareRepo}' does not exist`) + const shareJsonPath = path.join(localJson.shareRepo, '.syncshare.json') + ensureFileExists(shareJsonPath, `central .syncshare json: '${shareJsonPath}' does not exist`) + + const shareJson = loadJsonC(shareJsonPath) + mandatoryLocalKeys.forEach((prop) => { // ensure absence in shareJson + ensureFalse(!!shareJson[prop], `key: ${prop} must not be in shareJson`) }) + const minimumAggregateKeys = [ ...mandatoryLocalKeys, 'excludedExtensions', 'MAX_FILE_SIZE_MB'] + const combinedJSON = { ...defaultJson, - ...projectJson + ...localJson } + minimumAggregateKeys.forEach((prop) => { + ensureTruthy(combinedJSON[prop], `key: ${prop} must be in combinedJSON`) + }) + return combinedJSON } diff --git a/test/selftest.spec.js b/test/selfTest.spec.js similarity index 100% rename from test/selftest.spec.js rename to test/selfTest.spec.js diff --git a/test/simpleRun.spec.js b/test/testConfig.spec.js similarity index 62% rename from test/simpleRun.spec.js rename to test/testConfig.spec.js index 658f9d8..a1be5ef 100644 --- a/test/simpleRun.spec.js +++ b/test/testConfig.spec.js @@ -24,63 +24,78 @@ const wipeAndRecreateDir = (dir, label) => { ensureTrue(fs.readdirSync(dir).length === 0, 'test directory not empty') } +let synclocal // overriden in some (negative) tests + beforeEach(done => { wipeAndRecreateDir(LOCAL, 'LOCAL TESTDIR') wipeAndRecreateDir(SHARE, 'SHARE TESTDIR') - // make up a local repo, including syncdocs file: - const syncdocs = { + // prepare .synclocal.json + synclocal = { machineName: os.hostname(), - // NEXT: localRepo is not needed ! + localRepo: LOCAL, shareRepo: SHARE } fs.writeFileSync( path.join(LOCAL, '.synclocal.json'), - JSON.stringify(syncdocs, null, 2)) + JSON.stringify(synclocal, null, 2)) + + // prepare .syncshare.json + const syncshare = { + "MAX_FILE_SIZE_MB": 42, + } + + fs.writeFileSync( + path.join(SHARE, '.syncshare.json'), + JSON.stringify(syncshare, null, 2)) const DIRS = [LOCAL, SHARE] DIRS.forEach(DIR => { warn(`setting up ${DIR}`) process.chdir(DIR) guard('git init', { mute: true }) - - // NEXT `cp -r some stuff to both sides, then deviate }) process.chdir(LOCAL) // crucial for testing ! done() }) -describe('Main Script Execution', () => { - // const testFilePath = path.join(LOCAL, 'howdy.txt') - - // guard('ls -l .', {}) - // TEMP LATER guard(`node ${PROJECTROOT}/src/main.js`, {}) - // assert(fs.existsSync(testFilePath), `did not find ${testFilePath}`) - // if (error) { - // console.error(`exec error: ${error}`) - // return done(error) - // } - // // Check if howdy.txt has been created - // assert(fs.existsSync(testFilePath)) - // done() - // }) +describe('Config Tests', () => { it.only('should get reasonable config', function() { - console.log('howdy, partner!') - console.log('Current working directory:', process.cwd()) - + assert.strictEqual(process.cwd(), LOCAL) // ensure setup did not mess up const config = getConfig(process.cwd()) - // console.log('config:', config) - ensureTrue(typeof config.machineName === 'string' && config.machineName.length > 0, 'machineName is missing or empty'); - assert.strictEqual(config.localRepo, LOCAL); + ensureTrue(typeof config.machineName === 'string' && config.machineName.length > 0, 'machineName is missing or empty') + assert.strictEqual(config.localRepo, LOCAL) assert.strictEqual(config.shareRepo, SHARE) assert.deepStrictEqual(config.excludedExtensions, defaultConfig.excludedExtensions) - assert(Number.isInteger(config.MAX_FILE_SIZE_MB), 'MAX_FILE_SIZE_MB is not a whole number'); - assert(config.MAX_FILE_SIZE_MB >= 5 && config.MAX_FILE_SIZE_MB <= 300, 'MAX_FILE_SIZE_MB is not between 5 and 300'); + assert(Number.isInteger(config.MAX_FILE_SIZE_MB), 'MAX_FILE_SIZE_MB is not a whole number') + assert(config.MAX_FILE_SIZE_MB >= 5 && config.MAX_FILE_SIZE_MB <= 300, 'MAX_FILE_SIZE_MB is not between 5 and 300') }) + it('negative: referenced non-existing .syncshare', function() { + // TODO !!! + const config = getConfig(process.cwd()) + }) + + it('negative: to little in .synclocal', function() { + // TODO !!! + const config = getConfig(process.cwd()) + }) + + it('negative: to much in .synclocal', function() { + // TODO !!! + const config = getConfig(process.cwd()) + }) + + it('negative: to much in .synclocal', function() { + // TODO !!! + const config = getConfig(process.cwd()) + }) + + + })