diff --git a/packages/xo-remote-parser/.editorconfig b/packages/xo-remote-parser/.editorconfig new file mode 100644 index 000000000..da21ef4c5 --- /dev/null +++ b/packages/xo-remote-parser/.editorconfig @@ -0,0 +1,65 @@ +# http://EditorConfig.org +# +# Julien Fontanet's configuration +# https://gist.github.com/julien-f/8096213 + +# Top-most EditorConfig file. +root = true + +# Common config. +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespaces = true + +# CoffeeScript +# +# https://github.com/polarmobile/coffeescript-style-guide/blob/master/README.md +[*.{,lit}coffee] +indent_size = 2 +indent_style = space + +# Markdown +[*.{md,mdwn,mdown,markdown}] +indent_size = 4 +indent_style = space + +# Package.json +# +# This indentation style is the one used by npm. +[/package.json] +indent_size = 2 +indent_style = space + +# Jade +[*.jade] +indent_size = 2 +indent_style = space + +# JavaScript +# +# Two spaces seems to be the standard most common style, at least in +# Node.js (http://nodeguide.com/style.html#tabs-vs-spaces). +[*.js] +indent_size = 2 +indent_style = space + +# Less +[*.less] +indent_size = 2 +indent_style = space + +# Sass +# +# Style used for http://libsass.com +[*.s[ac]ss] +indent_size = 2 +indent_style = space + +# YAML +# +# Only spaces are allowed. +[*.yaml] +indent_size = 2 +indent_style = space diff --git a/packages/xo-remote-parser/.gitignore b/packages/xo-remote-parser/.gitignore new file mode 100644 index 000000000..6959be1cf --- /dev/null +++ b/packages/xo-remote-parser/.gitignore @@ -0,0 +1,9 @@ +/.nyc_output/ +/bower_components/ +/dist/ + +npm-debug.log +npm-debug.log.* + +!node_modules/* +node_modules/*/ diff --git a/packages/xo-remote-parser/.mocha.js b/packages/xo-remote-parser/.mocha.js new file mode 100644 index 000000000..e6d84e403 --- /dev/null +++ b/packages/xo-remote-parser/.mocha.js @@ -0,0 +1,5 @@ +Error.stackTraceLimit = 100 + +try { require('trace') } catch (_) {} +try { require('clarify') } catch (_) {} +try { require('source-map-support/register') } catch (_) {} diff --git a/packages/xo-remote-parser/.mocha.opts b/packages/xo-remote-parser/.mocha.opts new file mode 100644 index 000000000..6cfd94898 --- /dev/null +++ b/packages/xo-remote-parser/.mocha.opts @@ -0,0 +1 @@ +--require ./.mocha.js diff --git a/packages/xo-remote-parser/.npmignore b/packages/xo-remote-parser/.npmignore new file mode 100644 index 000000000..c31ee82cb --- /dev/null +++ b/packages/xo-remote-parser/.npmignore @@ -0,0 +1,10 @@ +/examples/ +example.js +example.js.map +*.example.js +*.example.js.map + +/test/ +/tests/ +*.spec.js +*.spec.js.map diff --git a/packages/xo-remote-parser/.travis.yml b/packages/xo-remote-parser/.travis.yml new file mode 100644 index 000000000..a9b136ea6 --- /dev/null +++ b/packages/xo-remote-parser/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - 'stable' + - '4' + - '0.12' + +# Use containers. +# http://docs.travis-ci.com/user/workers/container-based-infrastructure/ +sudo: false diff --git a/packages/xo-remote-parser/README.md b/packages/xo-remote-parser/README.md new file mode 100644 index 000000000..d811985b1 --- /dev/null +++ b/packages/xo-remote-parser/README.md @@ -0,0 +1,52 @@ +# ${pkg.name} [![Build Status](https://travis-ci.org/${pkg.shortGitHubPath}.png?branch=master)](https://travis-ci.org/${pkg.shortGitHubPath}) + +> ${pkg.description} + +## Install + +Installation of the [npm package](https://npmjs.org/package/${pkg.name}): + +``` +> npm install --save ${pkg.name} +``` + +## Usage + +**TODO** + +## Development + +### Installing dependencies + +``` +> npm install +``` + +### Compilation + +The sources files are watched and automatically recompiled on changes. + +``` +> npm run dev +``` + +### Tests + +``` +> npm run test-dev +``` + +## Contributions + +Contributions are *very* welcomed, either on the documentation or on +the code. + +You may: + +- report any [issue](${pkg.bugs}) + you've encountered; +- fork and create a pull request. + +## License + +${pkg.license} © [${pkg.author.name}](${pkg.author.url}) diff --git a/packages/xo-remote-parser/package.json b/packages/xo-remote-parser/package.json new file mode 100644 index 000000000..6adfde682 --- /dev/null +++ b/packages/xo-remote-parser/package.json @@ -0,0 +1,72 @@ +{ + "name": "xo-remote-parser", + "version": "0.3.0", + "license": "AGPL-3.0", + "description": "", + "keywords": [], + "homepage": "", + "bugs": "", + "repository": { + "type": "git", + "url": "https://github.com/vatesfr/xo-remote-parser" + }, + "author": { + "name": "Fabrice Marsaud", + "email": "fabrice.marsaud@vates.fr" + }, + "preferGlobal": false, + "main": "dist/", + "bin": {}, + "files": [ + "dist/" + ], + "engines": { + "node": ">=0.12" + }, + "dependencies": { + "lodash": "^4.13.1" + }, + "devDependencies": { + "babel-cli": "^6.3.17", + "babel-eslint": "^7.0.0", + "babel-preset-es2015": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "clarify": "^2.0.0", + "deep-freeze": "0.0.1", + "dependency-check": "^2.5.1", + "ghooks": "^1.2.1", + "mocha": "^3.0.0", + "must": "^0.13.1", + "nyc": "^10.0.0", + "source-map-support": "^0.4.0", + "standard": "^8.0.0", + "trace": "^2.1.0" + }, + "scripts": { + "build": "NODE_ENV=production babel --source-maps --out-dir=dist/ src/", + "depcheck": "dependency-check ./package.json", + "dev": "babel --watch --source-maps --out-dir=dist/ src/", + "dev-test": "mocha --opts .mocha.opts --watch --reporter=min \"dist/**/*.spec.js\"", + "lint": "standard", + "posttest": "npm run lint && npm run depcheck", + "prepublish": "npm run build", + "test": "nyc mocha --opts .mocha.opts \"dist/**/*.spec.js\"" + }, + "babel": { + "presets": [ + "stage-0", + "es2015" + ] + }, + "standard": { + "ignore": [ + "dist" + ], + "parser": "babel-eslint" + }, + "config": { + "ghooks": { + "commit-msg": "npm test" + } + } +} diff --git a/packages/xo-remote-parser/src/index.js b/packages/xo-remote-parser/src/index.js new file mode 100644 index 000000000..68993294d --- /dev/null +++ b/packages/xo-remote-parser/src/index.js @@ -0,0 +1,57 @@ +import filter from 'lodash/filter' +import map from 'lodash/map' +import trim from 'lodash/trim' +import trimStart from 'lodash/trimStart' + +const sanitizePath = (...paths) => filter(map(paths, s => s && filter(map(s.split('/'), trim)).join('/'))).join('/') + +export const parse = string => { + const object = { } + + const [type, rest] = string.split('://') + if (type === 'file') { + object.type = 'file' + object.path = `/${trimStart(rest, '/')}` // the leading slash has been forgotten on client side first implementation + } else if (type === 'nfs') { + object.type = 'nfs' + const [host, path] = rest.split(':') + object.host = host + object.path = `/${trimStart(path, '/')}` // takes care of a missing leading slash coming from previous version format + } else if (type === 'smb') { + object.type = 'smb' + const lastAtSign = rest.lastIndexOf('@') + const smb = rest.slice(lastAtSign + 1) + const auth = rest.slice(0, lastAtSign) + const firstColon = auth.indexOf(':') + const username = auth.slice(0, firstColon) + const password = auth.slice(firstColon + 1) + const [domain, sh] = smb.split('\\\\') + const [host, path] = sh.split('\0') + object.host = host + object.path = path + object.domain = domain + object.username = username + object.password = password + } + return object +} + +export const format = ({type, host, path, username, password, domain}) => { + type === 'local' && (type = 'file') + let string = `${type}://` + if (type === 'nfs') { + string += `${host}:` + } + if (type === 'smb') { + string += `${username}:${password}@${domain}\\\\${host}` + } + path = sanitizePath(path) + if (type === 'smb') { + path = path.split('/') + path = '\0' + path.join('\\') // FIXME saving with the windows fashion \ was a bad idea :,( + } else { + path = `/${path}` + } + string += path + return string +} diff --git a/packages/xo-remote-parser/src/index.spec.js b/packages/xo-remote-parser/src/index.spec.js new file mode 100644 index 000000000..d6f925f55 --- /dev/null +++ b/packages/xo-remote-parser/src/index.spec.js @@ -0,0 +1,92 @@ +/* eslint-env mocha */ + +import deepFreeze from 'deep-freeze' +import expect from 'must' + +// =================================================================== + +import { parse, format } from './' + +// =================================================================== + +// Data used for both parse and format (i.e. correctly formatted). +const data = deepFreeze({ + file: { + string: 'file:///var/lib/xoa/backup', + object: { + type: 'file', + path: '/var/lib/xoa/backup' + } + }, + SMB: { + string: 'smb://Administrator:pas:sw@ord@toto\\\\192.168.100.225\\smb\0', + object: { + type: 'smb', + host: '192.168.100.225\\smb', + path: '', + domain: 'toto', + username: 'Administrator', + password: 'pas:sw@ord' + } + }, + NFS: { + string: 'nfs://192.168.100.225:/media/nfs', + object: { + type: 'nfs', + host: '192.168.100.225', + path: '/media/nfs' + } + } +}) + +const parseData = deepFreeze({ + ...data, + + 'file with missing leading slash (#7)': { + string: 'file://var/lib/xoa/backup', + object: { + type: 'file', + path: '/var/lib/xoa/backup' + } + }, + 'nfs with missing leading slash': { + string: 'nfs://192.168.100.225:media/nfs', + object: { + type: 'nfs', + host: '192.168.100.225', + path: '/media/nfs' + } + } +}) + +const formatData = deepFreeze({ + ...data, + + 'file with local type': { + string: 'file:///var/lib/xoa/backup', + object: { + type: 'local', + path: '/var/lib/xoa/backup' + } + } +}) + +// ------------------------------------------------------------------- + +describe('format', () => { + for (const name in formatData) { + const datum = formatData[name] + it(name, () => { + expect(format(datum.object)).to.equal(datum.string) + }) + } +}) + +describe('parse', () => { + for (const name in parseData) { + const datum = parseData[name] + it(name, () => { + expect(parse(datum.string)).to.eql(datum.object) + }) + } +})