zotero-plugin 1.0.64 → 1.0.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/bin/start.py +135 -0
- package/package.json +3 -4
- package/bin/start.d.ts +0 -2
- package/bin/start.js +0 -70
package/README.md
CHANGED
|
@@ -27,3 +27,32 @@ to the current branch (or maybe your branch isn't named `gh-<number>`,
|
|
|
27
27
|
add `#<number>` to the commit message.
|
|
28
28
|
|
|
29
29
|
Release new versions by issuing `npm version <major|minor|patch>`.
|
|
30
|
+
|
|
31
|
+
# Starting Zotero with your plugin loaded
|
|
32
|
+
|
|
33
|
+
Note is is *much* adviced to create a separate Zotero profile for testing!
|
|
34
|
+
|
|
35
|
+
You will need to have python3 installed to use this.
|
|
36
|
+
|
|
37
|
+
Create a file called `zotero-plugin.ini` with the following contents:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
[profile]
|
|
41
|
+
name = <your test profile name>
|
|
42
|
+
path = <your test profile absolute path>
|
|
43
|
+
|
|
44
|
+
[zotero]
|
|
45
|
+
log = <file name to write log output to> # optional
|
|
46
|
+
db = <path to zotero.sqlite you want to populate the profile with> # optional
|
|
47
|
+
|
|
48
|
+
[preferences]
|
|
49
|
+
extensions.zotero.<your extension>.<some setting> = true
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
and add this script to your package.json:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
"start": "zotero-start"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
then when you execute `npm start`, zotero will start up with the latest build of your plugin installed.
|
package/bin/start.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import os, sys
|
|
4
|
+
import shutil
|
|
5
|
+
import json
|
|
6
|
+
import configparser
|
|
7
|
+
import argparse
|
|
8
|
+
import shlex
|
|
9
|
+
import xml.etree.ElementTree as ET
|
|
10
|
+
import subprocess
|
|
11
|
+
import collections
|
|
12
|
+
import types
|
|
13
|
+
import platform
|
|
14
|
+
|
|
15
|
+
class Config:
|
|
16
|
+
def __init__(self):
|
|
17
|
+
config_file = 'zotero-plugin.ini'
|
|
18
|
+
assert os.path.isfile(config_file), f'cannot find {config_file}'
|
|
19
|
+
|
|
20
|
+
config = configparser.ConfigParser(strict = False)
|
|
21
|
+
config.read(config_file)
|
|
22
|
+
|
|
23
|
+
self.profile = types.SimpleNamespace(
|
|
24
|
+
path=os.path.expanduser(config.get('profile', 'path')),
|
|
25
|
+
name=config.get('profile', 'name', fallback=None)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
self.zotero = types.SimpleNamespace(
|
|
29
|
+
path=config.get('zotero', 'path', fallback=None),
|
|
30
|
+
log=config.get('zotero', 'log', fallback=None),
|
|
31
|
+
db=config.get('profile', 'db', fallback=None)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if self.zotero.path:
|
|
35
|
+
self.zotero.path = os.path.expanduser(self.zotero.path)
|
|
36
|
+
elif platform.system() == 'Darwin':
|
|
37
|
+
self.zotero.path = '/Applications/Zotero.app/Contents/MacOS/zotero'
|
|
38
|
+
elif platform.system() == 'Linux':
|
|
39
|
+
self.zotero.path = '/usr/lib/zotero/zotero'
|
|
40
|
+
else:
|
|
41
|
+
assert False, f'{platform.system()} not supported'
|
|
42
|
+
|
|
43
|
+
if self.zotero.log:
|
|
44
|
+
self.zotero.log = os.path.expanduser(self.zotero.log)
|
|
45
|
+
|
|
46
|
+
if 'preferences' in config:
|
|
47
|
+
self.preference = { k: self.pref_value(v) for k, v in dict(config['preferences']).items() }
|
|
48
|
+
else:
|
|
49
|
+
self.preference = {}
|
|
50
|
+
|
|
51
|
+
# always set these
|
|
52
|
+
self.preference['extensions.autoDisableScopes']= 0
|
|
53
|
+
self.preference['extensions.enableScopes'] = 15
|
|
54
|
+
self.preference['extensions.startupScanScopes'] = 15
|
|
55
|
+
self.preference['extensions.zotero.debug.log'] = True
|
|
56
|
+
# null deletes if present
|
|
57
|
+
self.preference['extensions.lastAppBuildId'] = None
|
|
58
|
+
self.preference['extensions.lastAppVersion'] = None
|
|
59
|
+
|
|
60
|
+
def pref_value(self, v):
|
|
61
|
+
if v in ['true', 'false']: return v == 'true'
|
|
62
|
+
if v == 'null': return None
|
|
63
|
+
try:
|
|
64
|
+
return int(v)
|
|
65
|
+
except ValueError:
|
|
66
|
+
pass
|
|
67
|
+
try:
|
|
68
|
+
return float(v)
|
|
69
|
+
except ValueError:
|
|
70
|
+
pass
|
|
71
|
+
try:
|
|
72
|
+
return json.loads(v)
|
|
73
|
+
except json.decoder.JSONDecodeError:
|
|
74
|
+
pass
|
|
75
|
+
return v
|
|
76
|
+
config = Config()
|
|
77
|
+
|
|
78
|
+
def patch_prefs(prefs, add_config):
|
|
79
|
+
def name(line):
|
|
80
|
+
if not line.startswith('user_pref('): return None
|
|
81
|
+
if not line.startswith('user_pref("'): raise ValueError('unexpected user pref: ' + line)
|
|
82
|
+
open_quote = None
|
|
83
|
+
for i, c in enumerate(line):
|
|
84
|
+
if c == '"':
|
|
85
|
+
if open_quote is None:
|
|
86
|
+
open_quote = i
|
|
87
|
+
else:
|
|
88
|
+
try:
|
|
89
|
+
return json.loads(line[open_quote : i + 1])
|
|
90
|
+
except json.decoder.JSONDecodeError:
|
|
91
|
+
pass
|
|
92
|
+
raise ValueError('unexpected user pref: ' + line)
|
|
93
|
+
|
|
94
|
+
prefs = os.path.join(config.profile.path, f'{prefs}.js')
|
|
95
|
+
if not os.path.exists(prefs): return
|
|
96
|
+
|
|
97
|
+
user_prefs = []
|
|
98
|
+
with open(prefs) as f:
|
|
99
|
+
for line in f.readlines():
|
|
100
|
+
if name(line) not in config.preference:
|
|
101
|
+
user_prefs.append(line)
|
|
102
|
+
if add_config:
|
|
103
|
+
for key, value in config.preference.items():
|
|
104
|
+
if value is not None:
|
|
105
|
+
user_prefs.append(f'user_pref({json.dumps(key)}, {json.dumps(value)});\n')
|
|
106
|
+
|
|
107
|
+
with open(prefs, 'w') as f:
|
|
108
|
+
f.write(''.join(user_prefs))
|
|
109
|
+
|
|
110
|
+
patch_prefs('prefs', False)
|
|
111
|
+
patch_prefs('user', True)
|
|
112
|
+
|
|
113
|
+
def system(cmd):
|
|
114
|
+
print('$', cmd)
|
|
115
|
+
subprocess.run(cmd, shell=True, check=True)
|
|
116
|
+
|
|
117
|
+
system('npm run build')
|
|
118
|
+
|
|
119
|
+
if config.zotero.db:
|
|
120
|
+
shutil.copyfile(config.zotero.db, os.path.join(config.profile.path, 'zotero', 'zotero.sqlite'))
|
|
121
|
+
|
|
122
|
+
for plugin_id in ET.parse(os.path.join('build', 'install.rdf')).getroot().findall('{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description/{http://www.mozilla.org/2004/em-rdf#}id'):
|
|
123
|
+
plugin_path = os.path.join(config.profile.path, 'extensions', plugin_id.text)
|
|
124
|
+
with open(plugin_path, 'w') as f:
|
|
125
|
+
sources = os.path.join(os.getcwd(), 'build')
|
|
126
|
+
if sources[-1] != '/': sources += '/'
|
|
127
|
+
print(sources, file=f)
|
|
128
|
+
|
|
129
|
+
cmd = config.zotero.path + ' -purgecaches -P'
|
|
130
|
+
if config.profile.name: cmd += ' ' + shlex.quote(config.profile.name)
|
|
131
|
+
cmd += ' -jsconsole -ZoteroDebugText -datadir profile'
|
|
132
|
+
if config.zotero.log: cmd += ' > ' + shlex.quote(config.zotero.log)
|
|
133
|
+
cmd += ' &'
|
|
134
|
+
|
|
135
|
+
system(cmd)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zotero-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.65",
|
|
4
4
|
"description": "Zotero plugin builder",
|
|
5
5
|
"homepage": "https://github.com/retorquere/zotero-plugin/wiki",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"zotero-plugin-zipup": "bin/zipup.js",
|
|
9
9
|
"zotero-plugin-link": "bin/link.js",
|
|
10
10
|
"issue-branches": "bin/branches.js",
|
|
11
|
-
"zotero-start": "bin/start.
|
|
11
|
+
"zotero-start": "bin/start.py"
|
|
12
12
|
},
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Emiliano Heyns",
|
|
@@ -67,8 +67,6 @@
|
|
|
67
67
|
},
|
|
68
68
|
"license": "ISC",
|
|
69
69
|
"files": [
|
|
70
|
-
"bin/start.d.ts",
|
|
71
|
-
"bin/start.js",
|
|
72
70
|
"bin/branches.d.ts",
|
|
73
71
|
"bin/branches.js",
|
|
74
72
|
"bin/link.d.ts",
|
|
@@ -77,6 +75,7 @@
|
|
|
77
75
|
"bin/release.js",
|
|
78
76
|
"bin/zipup.d.ts",
|
|
79
77
|
"bin/zipup.js",
|
|
78
|
+
"bin/start.py",
|
|
80
79
|
"continuous-integration.d.ts",
|
|
81
80
|
"continuous-integration.js",
|
|
82
81
|
"copy-assets.d.ts",
|
package/bin/start.d.ts
DELETED
package/bin/start.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/* eslint-disable no-console, prefer-template, @typescript-eslint/no-unsafe-argument, @typescript-eslint/restrict-plus-operands */
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
const tslib_1 = require("tslib");
|
|
6
|
-
const fs = (0, tslib_1.__importStar)(require("fs"));
|
|
7
|
-
const path = (0, tslib_1.__importStar)(require("path"));
|
|
8
|
-
const child_process_1 = require("child_process");
|
|
9
|
-
const shell_quote_1 = require("shell-quote");
|
|
10
|
-
const clp_1 = (0, tslib_1.__importDefault)(require("clp"));
|
|
11
|
-
function quote(args) {
|
|
12
|
-
return (0, shell_quote_1.quote)(args); // eslint-disable-line @typescript-eslint/no-unsafe-call
|
|
13
|
-
}
|
|
14
|
-
const argv = clp_1.default();
|
|
15
|
-
const root_1 = (0, tslib_1.__importDefault)(require("../root"));
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
17
|
-
const profile = require(path.join(root_1.default, 'profile.json'));
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
19
|
-
const pkg = require(path.join(root_1.default, 'package.json'));
|
|
20
|
-
function exec(cmd) {
|
|
21
|
-
console.log(cmd);
|
|
22
|
-
if (!argv.dryRun)
|
|
23
|
-
(0, child_process_1.execSync)(cmd, { stdio: 'inherit' });
|
|
24
|
-
}
|
|
25
|
-
if (argv.reset) {
|
|
26
|
-
const settings = {
|
|
27
|
-
replace: {
|
|
28
|
-
'extensions.autoDisableScopes': 0,
|
|
29
|
-
'extensions.enableScopes': 15,
|
|
30
|
-
'extensions.startupScanScopes': 15,
|
|
31
|
-
},
|
|
32
|
-
remove: [
|
|
33
|
-
'extensions.lastAppBuildId',
|
|
34
|
-
'extensions.lastAppVersion',
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
const remove = new RegExp(settings.remove.concat(Object.keys(settings)).map(setting => setting.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'));
|
|
38
|
-
for (const prefs of ['user', 'prefs']) {
|
|
39
|
-
const user_prefs = [];
|
|
40
|
-
for (const user_pref of fs.readFileSync(path.join(profile.dir, `${prefs}.js`), 'utf-8').split('\n')) {
|
|
41
|
-
if (!user_pref.match(remove))
|
|
42
|
-
user_prefs.push(user_pref);
|
|
43
|
-
}
|
|
44
|
-
for (const [user_pref, value] of Object.entries(settings.replace)) {
|
|
45
|
-
user_prefs.push(`user_pref("${user_pref}", ${value});`);
|
|
46
|
-
}
|
|
47
|
-
fs.writeFileSync(path.join(profile.dir, `${prefs}.js`), user_prefs.join('\n'));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
exec('npm run build');
|
|
51
|
-
exec(quote(['rm', '-rf', path.join(profile.dir, 'extensions.json')]));
|
|
52
|
-
exec(quote(['rm', '-rf', path.join(profile.dir, 'extensions')]) + path.sep + pkg.name + '*.xpi');
|
|
53
|
-
let code = path.resolve(path.join(root_1.default, 'build'));
|
|
54
|
-
if (!code.endsWith(path.sep))
|
|
55
|
-
code += path.sep;
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
|
57
|
-
fs.writeFileSync(path.join(profile.dir, 'extensions', pkg.name.replace('zotero-', '') + pkg.author.email.replace(/.*@/, '@')), code);
|
|
58
|
-
let zotero = null;
|
|
59
|
-
switch (process.platform) {
|
|
60
|
-
case 'darwin':
|
|
61
|
-
zotero = '/Applications/Zotero.app/Contents/MacOS/zotero';
|
|
62
|
-
break;
|
|
63
|
-
case 'win32':
|
|
64
|
-
console.log('not implemented on windows');
|
|
65
|
-
process.exit(1);
|
|
66
|
-
default:
|
|
67
|
-
zotero = '/usr/local/bin/zotero/zotero';
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
exec(quote([zotero, '-purgecaches', '-P', profile.name, '-jsconsole', '-ZoteroDebugText']) + ' > ' + quote([profile.log]));
|