Building extension files

Adds possibility to build extension files (Chrome and Safari) from
command line.

To run from the project directory:
python tools/build.py [meta]

If the optional `meta` argument is set, then only the manifest and
language files are uptated.
Without that everything is being built (extension files too) into the
`dist/build/version_number` folder.

For Chrome there will be two files, a crx, and a .zip file which
includes the key.pem private key (so this must not be shared,
it's just a bit help for publishing it to the Chrome Web Store).

Beside the extension files, update-files are generated too (for self
hosting - Safari needs it).
This commit is contained in:
Deathamns 2014-11-09 17:50:58 +01:00
parent 4bf6664d6b
commit 0d9d285608
20 changed files with 406 additions and 211 deletions

View File

@ -1,29 +1,29 @@
{ {
"name": "µBlock", "name": "µBlock",
"clean_name": "ublock", "clean_name": "uBlock",
"url": "https://github.com/gorhill/uBlock", "url": "https://github.com/gorhill/uBlock",
"author": "Raymond Hill", "author": "Raymond Hill",
"author_email": "rhill@raymondhill.net", "author_email": "rhill@raymondhill.net",
"version": "0.7.0.9", "version": "0.7.0.10",
"def_lang": "en", "def_lang": "en",
"vendors": { "vendors": {
"crx": { "crx": {
"app_id": "cjpalhdlnbpafiamejdnhcphjbkeiagm", "app_id": "cjpalhdlnbpafiamejdnhcphjbkeiagm",
"manifest": "manifest.json", "manifest": "manifest.json",
"locales": "_locales", "locales": "_locales",
"file_ext": ".crx", "file_ext": ".crx",
"cert_key": "../meta/crx/key.pem" "private_key": "./meta/crx/key.pem"
}, },
"safariextz": { "safariextz": {
"app_id": "net.gorhill.uBlock", "app_id": "net.gorhill.uBlock",
"manifest": { "manifest": {
"Info": "Info.plist", "Info": "Info.plist",
"Settings": "Settings.plist" "Settings": "Settings.plist"
}, },
"file_ext": ".safariextz", "file_ext": ".safariextz",
"developer_identifier": "", "developer_identifier": "",
"cert_dir": "../meta/safariextz/certs/", "cert_dir": "./meta/safariextz/certs/",
"cert_key": "../meta/safariextz/certs/key.pem" "private_key": "./meta/safariextz/key.pem"
} }
} }
} }

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0"> <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
<app appid="{app_id}"> <app appid="{app_id}">
<updatecheck codebase="{url}{name}.crx" version="{version}"/> <updatecheck codebase="{url}/{name}.crx" version="{version}"/>
</app> </app>
</gupdate> </gupdate>

View File

@ -14,7 +14,7 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>{build_number}</string> <string>{build_number}</string>
<key>URL</key> <key>URL</key>
<string>{url}{name}.safariextz</string> <string>{url}/{name}.safariextz</string>
</dict> </dict>
</array> </array>
</dict> </dict>

View File

@ -13,9 +13,9 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.7.0.9</string> <string>0.7.0.10</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1455425</string> <string>1456132</string>
<key>Chrome</key> <key>Chrome</key>
<dict> <dict>
<key>Database Quota</key> <key>Database Quota</key>

View File

@ -8,7 +8,7 @@ div > p:last-child {
font-size: smaller; font-size: smaller;
width: 48em; width: 48em;
height: 40em; height: 40em;
white-space: nowrap; white-space: pre;
text-align: left; text-align: left;
} }
#whitelist.bad { #whitelist.bad {

View File

@ -28,10 +28,10 @@
uDom.onLoad(function() { uDom.onLoad(function() {
uDom('[data-i18n]').forEach(function(elem) { uDom('[data-i18n]').forEach(function(elem) {
elem.html(vAPI.i18n.getMessage(elem.attr('data-i18n'))); elem.html(vAPI.i18n(elem.attr('data-i18n')));
}); });
uDom('[title]').forEach(function(elem) { uDom('[title]').forEach(function(elem) {
var title = vAPI.i18n.getMessage(elem.attr('title')); var title = vAPI.i18n(elem.attr('title'));
if ( title ) { if ( title ) {
elem.attr('title', title); elem.attr('title', title);
} }
@ -39,7 +39,7 @@ uDom.onLoad(function() {
uDom('[data-i18n-tip]').forEach(function(elem) { uDom('[data-i18n-tip]').forEach(function(elem) {
elem.attr( elem.attr(
'data-tip', 'data-tip',
vAPI.i18n.getMessage(elem.attr('data-i18n-tip')).replace(/<br>/g, '') vAPI.i18n(elem.attr('data-i18n-tip')).replace(/<br>/g, '')
); );
}); });
}); });

View File

@ -5,6 +5,6 @@ self.vAPI = self.vAPI || {};
vAPI.app = { vAPI.app = {
/**/name: 'µBlock', /**/name: 'µBlock',
/**/version: '0.7.0.9', /**/version: '0.7.0.10',
/**/url: 'https://github.com/gorhill/uBlock', /**/url: 'https://github.com/gorhill/uBlock',
}; };

View File

@ -1,3 +1,4 @@
// » header
/* global SafariBrowserTab, Services, XPCOMUtils */ /* global SafariBrowserTab, Services, XPCOMUtils */
// for background page only // for background page only
@ -5,8 +6,10 @@
'use strict'; 'use strict';
self.vAPI = self.vAPI || {}; self.vAPI = self.vAPI || {};
// «
if (self.chrome) { if (self.chrome) {
// » crx
var chrome = self.chrome; var chrome = self.chrome;
vAPI.chrome = true; vAPI.chrome = true;
@ -272,7 +275,9 @@ if (self.chrome) {
chrome.contextMenus.remove(this.menuId); chrome.contextMenus.remove(this.menuId);
} }
}; };
// «
} else if (self.safari) { } else if (self.safari) {
// » safariextz
vAPI.safari = true; vAPI.safari = true;
// addContentScriptFromURL allows whitelisting, // addContentScriptFromURL allows whitelisting,
@ -888,9 +893,13 @@ if (self.chrome) {
this.onContextMenuCommand = null; this.onContextMenuCommand = null;
} }
}; };
// «
} }
// » footer
if (!self.chrome) { if (!self.chrome) {
self.chrome = { runtime: { lastError: null } }; self.chrome = { runtime: { lastError: null } };
} }
})(); })();
// «

View File

@ -1,3 +1,4 @@
// » header
/* global addMessageListener, removeMessageListener, sendAsyncMessage */ /* global addMessageListener, removeMessageListener, sendAsyncMessage */
// for non background pages // for non background pages
@ -51,8 +52,10 @@ var messagingConnector = function(response) {
var uniqueId = function() { var uniqueId = function() {
return parseInt(Math.random() * 1e10, 10).toString(36); return parseInt(Math.random() * 1e10, 10).toString(36);
}; };
// «
if (self.chrome) { if (self.chrome) {
// » crx
vAPI.chrome = true; vAPI.chrome = true;
vAPI.messaging = { vAPI.messaging = {
port: null, port: null,
@ -60,15 +63,14 @@ if (self.chrome) {
listeners: {}, listeners: {},
requestId: 0, requestId: 0,
connectorId: uniqueId(), connectorId: uniqueId(),
connector: messagingConnector,
setup: function() { setup: function() {
this.port = chrome.runtime.connect({name: this.connectorId}); this.port = chrome.runtime.connect({name: this.connectorId});
this.port.onMessage.addListener(this.connector); this.port.onMessage.addListener(messagingConnector);
}, },
close: function() { close: function() {
if (this.port) { if (this.port) {
this.port.disconnect(); this.port.disconnect();
this.port.onMessage.removeListener(this.connector); this.port.onMessage.removeListener(messagingConnector);
this.port = this.channels = this.listeners = this.connectorId = null; this.port = this.channels = this.listeners = this.connectorId = null;
} }
}, },
@ -105,7 +107,9 @@ if (self.chrome) {
return this.channels[channelName]; return this.channels[channelName];
} }
}; };
// «
} else if (self.safari) { } else if (self.safari) {
// » safariextz
vAPI.safari = true; vAPI.safari = true;
// relevant? // relevant?
@ -115,7 +119,6 @@ if (self.chrome) {
listeners: {}, listeners: {},
requestId: 0, requestId: 0,
connectorId: uniqueId(), connectorId: uniqueId(),
connector: messagingConnector,
setup: function() { setup: function() {
this._connector = function(msg) { this._connector = function(msg) {
// messages from the background script are sent to every frame, // messages from the background script are sent to every frame,
@ -123,7 +126,7 @@ if (self.chrome) {
// what is meant for the current context // what is meant for the current context
if (msg.name === vAPI.messaging.connectorId if (msg.name === vAPI.messaging.connectorId
|| msg.name === 'broadcast') { || msg.name === 'broadcast') {
vAPI.messaging.connector(msg.message); messagingConnector(msg.message);
} }
}; };
safari.self.addEventListener('message', this._connector, false); safari.self.addEventListener('message', this._connector, false);
@ -174,7 +177,7 @@ if (self.chrome) {
target: { target: {
page: { page: {
dispatchMessage: function(name, msg) { dispatchMessage: function(name, msg) {
vAPI.messaging.connector(msg); messagingConnector(msg);
} }
} }
} }
@ -371,6 +374,8 @@ if (self.chrome) {
url: window.location.href, url: window.location.href,
type: 'main_frame' type: 'main_frame'
}); });
// «
} }
// » footer
})(); })();
// «

View File

@ -1,3 +1,4 @@
// » header
// could be used for background and other extension pages // could be used for background and other extension pages
(function() { (function() {
@ -37,8 +38,10 @@ vAPI.download = function(details) {
messager.close(); messager.close();
} }
}; };
// «
if (self.chrome) { if (self.chrome) {
// » crx
var chrome = self.chrome; var chrome = self.chrome;
vAPI.getURL = function(path) { vAPI.getURL = function(path) {
@ -50,7 +53,9 @@ if (self.chrome) {
}; };
setScriptDirection(vAPI.i18n('@@ui_locale')); setScriptDirection(vAPI.i18n('@@ui_locale'));
// «
} else if (self.safari) { } else if (self.safari) {
// » safariextz
vAPI.getURL = function(path) { vAPI.getURL = function(path) {
return safari.extension.baseURI + path; return safari.extension.baseURI + path;
}; };
@ -119,6 +124,8 @@ if (self.chrome) {
} }
}); });
} }
// «
} }
// » footer
})(); })();
// «

View File

@ -58,10 +58,6 @@ exports.restart = function() {
if (vAPI.chrome) { if (vAPI.chrome) {
chrome.runtime.reload(); chrome.runtime.reload();
} }
// TODO? for cross-browser solution:
// window.location.reload();
// plus close all extension tabs
}; };
/******************************************************************************/ /******************************************************************************/

View File

@ -1 +1 @@
{"_": "en", "ar": 1, "cs": 1, "da": 1, "de": 1, "el": 1, "en": 1, "es": 1, "et": 1, "fi": 1, "fr": 1, "he": 1, "hr": 1, "hu": 1, "id": 1, "it": 1, "ja": 1, "nb": 1, "nl": 1, "pl": 1, "pt-BR": 1, "pt-PT": 1, "ro": 1, "ru": 1, "sv": 1, "tr": 1, "uk": 1, "vi": 1, "zh-CN": 1} {"_": "en", "ar": 1, "cs": 1, "da": 1, "de": 1, "el": 1, "en": 1, "es": 1, "et": 1, "fi": 1, "fr": 1, "he": 1, "hi": 1, "hr": 1, "hu": 1, "id": 1, "it": 1, "ja": 1, "mr": 1, "nb": 1, "nl": 1, "pl": 1, "pt-BR": 1, "pt-PT": 1, "ro": 1, "ru": 1, "sv": 1, "tr": 1, "uk": 1, "vi": 1, "zh-CN": 1}

View File

@ -58,4 +58,4 @@
"default_title": "µBlock", "default_title": "µBlock",
"default_popup": "popup.html" "default_popup": "popup.html"
} }
} }

263
tools/build.py Normal file
View File

@ -0,0 +1,263 @@
#!/usr/bin/env python3
import os
import re
import json
import glob
import sys
import subprocess
from time import strftime
from datetime import datetime
from shutil import which as iscmd, rmtree as rmt, copytree, copy, move
from collections import OrderedDict
from xml.sax.saxutils import escape
osp = os.path
pj = osp.join
os.chdir(pj(osp.split(osp.abspath(__file__))[0], '..'))
def rmtree(path):
if osp.exists(path):
rmt(path)
def mkdirs(path):
try:
os.makedirs(path)
finally:
return osp.exists(path)
def readfile(path, mode='rt'):
with open(path, mode) as f:
return f.read()
src_dir = osp.abspath(pj('src'))
meta_dir = osp.abspath(pj('meta'))
tmp_dir = osp.abspath(pj('tmp'))
with open(pj(meta_dir, 'config.json'), encoding='utf-8') as f:
config = json.load(f)
vendors = config['vendors']
del config['vendors']
tmp = datetime.now() - datetime(year=datetime.today().year, month=1, day=1)
config['build_number'] = strftime('%y' + str(int(tmp.total_seconds() * 65535 / 31536000)).zfill(5))
descriptions = OrderedDict({})
source_locale_dir = pj('src', '_locales')
build_tmp = pj(tmp_dir, config['clean_name'])
build_dir = osp.abspath(pj('dist', 'build', config['version']))
# fill 'descriptions'
for alpha2 in os.listdir(source_locale_dir):
with open(pj(source_locale_dir, alpha2, 'messages.json'), encoding='utf-8') as f:
string_data = json.load(f, object_pairs_hook=OrderedDict)
descriptions[alpha2] = string_data['extShortDesc']['message']
# only needed for Safari
with open(pj(src_dir, 'locales.json'), 'wt', encoding='utf-8', newline='\n') as f:
tmp = {
'_': config['def_lang']
}
for alpha2 in descriptions:
tmp[alpha2] = 1
json.dump(tmp, f, sort_keys=True, ensure_ascii=False)
with open(pj(src_dir, 'js', 'vapi-appinfo.js'), 'r+t', encoding='utf-8', newline='\n') as f:
tmp = f.read()
f.seek(0)
f.write(re.sub(
r'/\*\*/([^:]+:).+',
lambda m: '/**/' + m.group(1) + " '" + config[m.group(1)[:-1]] + "',",
tmp
))
with open(pj(src_dir, vendors['crx']['manifest']), 'wt', encoding='utf-8', newline='\n') as f:
cf_content = readfile(pj(meta_dir, 'crx', vendors['crx']['manifest']))
f.write(
re.sub(r"\{(?=\W)|(?<=\W)\}", r'\g<0>\g<0>', cf_content).format(**config)
)
with open(pj(src_dir, vendors['safariextz']['manifest']['Info']), 'wt', encoding='utf-8', newline='\n') as f:
config['app_id'] = vendors['safariextz']['app_id']
config['description'] = descriptions[config['def_lang']]
cf_content = readfile(pj(meta_dir, 'safariextz', vendors['safariextz']['manifest']['Info']))
f.write(cf_content.format(**config))
copy(pj(meta_dir, 'safariextz', vendors['safariextz']['manifest']['Settings']), pj(src_dir, vendors['safariextz']['manifest']['Settings']))
if 'meta' in sys.argv:
raise SystemExit('Metadata generated.')
rmtree(tmp_dir)
mkdirs(tmp_dir)
rmtree(build_dir)
mkdirs(build_dir)
# create update meta
for vendor, ext in {'crx': 'xml', 'safariextz': 'plist'}.items():
with open(pj(build_dir, 'update_' + vendor + '.' + ext), 'wt', encoding='utf-8', newline='\n') as f:
if vendor == 'safariextz':
config['developer_identifier'] = vendors[vendor]['developer_identifier']
config['app_id'] = vendors[vendor]['app_id']
cf_content = readfile(pj(meta_dir, vendor, 'update_' + vendor + '.' + ext))
f.write(cf_content.format(**config))
f.close()
# separate vendor specific code
for vapijsfile in [pj(src_dir, 'js', 'vapi-' + jsfile + '.js') for jsfile in ['background', 'common', 'client']]:
vapijs = readfile(vapijsfile)
# "» name" is the start marker, "«" is the end marker
js_parts = re.findall(r'»\s*(\w+)\n([^«]+)//', vapijs)
if not js_parts:
continue
js_header = js_parts.pop(0)[1]
js_footer = js_parts.pop()[1]
for js in js_parts:
with open(pj(tmp_dir, js[0] + '_' + osp.basename(vapijsfile)), 'wt', encoding='utf-8', newline='\n') as f:
f.write(js_header)
f.write(re.sub(r'^ ', '', js[1], flags=re.M))
f.write(js_footer)
def move_vendor_specific_js(vendor):
for file in ['background', 'common', 'client']:
move(pj(tmp_dir, vendor + '_vapi-' + file + '.js'), pj(build_tmp, 'js', 'vapi-' + file + '.js'))
def copy_vendor_files(files):
for file in files:
path = pj(src_dir, file)
if osp.isdir(path):
copytree(path, pj(build_tmp, file), copy_function=copy)
else:
copy(path, pj(build_tmp, file))
def remove_vendor_files(files):
for file in files:
path = pj(build_tmp, file)
if osp.isdir(path):
rmtree(path)
else:
os.remove(path)
def norm_cygdrive(path):
return '/cygdrive/' + path[0] + path[2:].replace('\\', '/') if path[1] == ':' else path
mkdirs(build_tmp)
for file in glob.iglob(pj(src_dir, '*')):
basename = osp.basename(file)
if osp.isfile(file) and (file.endswith('.html') or basename == 'icon.png'):
copy(file, pj(build_tmp, basename))
elif osp.isdir(file) and basename not in ['_locales', 'locale']:
copytree(file, pj(build_tmp, basename), copy_function=copy)
os.remove(pj(build_tmp, 'js', 'sitepatch-safari.js'))
package_name = config['clean_name'] + '-' + config['version']
# Chrome
if not iscmd('7z'):
print('Cannot build for Chrome: `7z` command not found.')
else:
vendor_files = ['_locales', 'manifest.json']
move_vendor_specific_js('crx')
copy_vendor_files(vendor_files)
package = pj(build_dir, package_name + '.zip')
subprocess.call('7z a -r -tzip -mx=8 "' + norm_cygdrive(package) + '" "' + norm_cygdrive(pj(build_tmp, '*')) + '"', stdout=subprocess.DEVNULL)
if osp.exists(vendors['crx']['private_key']):
if not iscmd('openssl'):
print('Cannot build for Chrome: `openssl` command not found.')
else:
# Convert the PEM key to DER (and extract the public form) for inclusion in the CRX header
derkey = subprocess.Popen([
'openssl', 'rsa', '-pubout',
'-inform', 'PEM',
'-outform', 'DER',
'-in', norm_cygdrive(vendors['crx']['private_key'])
], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.read()
# Sign the zip file with the private key in PEM format
signature = subprocess.Popen([
'openssl', 'sha1',
'-sign', norm_cygdrive(vendors['crx']['private_key']),
norm_cygdrive(package)
], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.read()
out = open(package.replace('.zip', vendors['crx']['file_ext']), "wb")
# Extension file magic number
out.write(bytes("Cr24\x02\x00\x00\x00", 'UTF-8') + len(derkey).to_bytes(4, 'little') + len(signature).to_bytes(4, 'little'))
out.write(derkey)
out.write(signature)
out.write(readfile(package, 'rb'))
out.close()
subprocess.call('7z a ' + norm_cygdrive(package) + ' ' + norm_cygdrive(osp.abspath(vendors['crx']['private_key'])), stdout=subprocess.DEVNULL)
remove_vendor_files(vendor_files)
# Safari
if not iscmd('xar'):
print('Cannot build for Safari: `xar` command not found.')
elif osp.exists(vendors['safariextz']['cert_dir']):
vendor_files = ['_locales', 'Info.plist', 'Settings.plist', pj('js', 'sitepatch-safari.js')]
move_vendor_specific_js('safariextz')
copy_vendor_files(vendor_files)
build_tmp = move(build_tmp, pj(tmp_dir, config['clean_name'] + '.safariextension'))
# xar accepts only unix style directory separators
package = pj(build_dir, package_name + vendors['safariextz']['file_ext']).replace('\\', '/');
subprocess.call('xar -czf "' + package + '" --compression-args=9 --distribution --directory="' + osp.basename(tmp_dir) + '" ' + config['clean_name'] + '.safariextension', stderr=subprocess.DEVNULL)
subprocess.call('xar --sign -f "' + package + '" --digestinfo-to-sign sfr_digest.dat --sig-size 256 ' + ' '.join('--cert-loc="' + vendors['safariextz']['cert_dir'] + 'cert0{0}"'.format(i) for i in range(3)), stderr=subprocess.DEVNULL)
subprocess.call('openssl rsautl -sign -inkey ' + vendors['safariextz']['private_key'] + ' -in sfr_digest.dat -out sfr_sig.dat', stderr=subprocess.DEVNULL)
subprocess.call('xar --inject-sig sfr_sig.dat -f "' + package + '"', stderr=subprocess.DEVNULL)
os.remove('sfr_sig.dat')
os.remove('sfr_digest.dat')
build_tmp = move(build_tmp, pj(tmp_dir, config['clean_name']))
remove_vendor_files(vendor_files)
rmtree(tmp_dir)
print("Files ready @ " + build_dir)

View File

@ -1,85 +0,0 @@
#!/usr/bin/env python3
import os
import re
import json
from time import strftime
from datetime import datetime
from shutil import rmtree as rmt, copy
from collections import OrderedDict
from xml.sax.saxutils import escape
osp = os.path
pj = osp.join
os.chdir('..')
def rmtree(path):
if osp.exists(path):
rmt(path)
def mkdirs(path):
try:
os.makedirs(path)
finally:
return osp.exists(path)
src_dir = pj('src')
meta_dir = pj('meta')
with open(pj(meta_dir, 'config.json'), encoding='utf-8') as f:
config = json.load(f)
vendors = config['vendors']
del config['vendors']
tmp = datetime.now() - datetime(year=datetime.today().year, month=1, day=1)
config['build_number'] = strftime('%y' + str(int(tmp.total_seconds() * 65535 / 31536000)).zfill(5))
descriptions = OrderedDict({})
with open(pj(src_dir, 'js', 'vapi-appinfo.js'), 'r+t', encoding='utf-8', newline='\n') as f:
tmp = f.read()
f.seek(0)
f.write(re.sub(
r'/\*\*/([^:]+:).+',
lambda m: '/**/' + m.group(1) + " '" + config[m.group(1)[:-1]] + "',",
tmp
))
with open(pj(src_dir, vendors['crx']['manifest']), 'wt', encoding='utf-8', newline='\n') as f:
with open(pj(meta_dir, 'crx', vendors['crx']['manifest']), 'r') as cf:
cf_content = cf.read()
f.write(
re.sub(r"\{(?=\W)|(?<=\W)\}", r'\g<0>\g<0>', cf_content).format(**config)
)
with open(pj(src_dir, 'locales.json'), 'wt', encoding='utf-8', newline='\n') as f:
tmp = {
'_': config['def_lang']
}
for alpha2 in descriptions:
tmp[alpha2] = 1
json.dump(tmp, f, sort_keys=True, ensure_ascii=False)
with open(pj(src_dir, vendors['safariextz']['manifest']['Info']), 'wt', encoding='utf-8', newline='\n') as f:
config['app_id'] = vendors['safariextz']['app_id']
config['description'] = descriptions[config['def_lang']]
with open(pj(meta_dir, 'safariextz', vendors['safariextz']['manifest']['Info']), 'r') as cf:
cf_content = cf.read()
f.write(cf_content.format(**config))
copy(pj(meta_dir, 'safariextz', vendors['safariextz']['manifest']['Settings']), pj(src_dir, vendors['safariextz']['manifest']['Settings']))

View File

@ -5,61 +5,61 @@
echo "*** uBlock: Importing from Crowdin archive" echo "*** uBlock: Importing from Crowdin archive"
rm -r ~/Downloads/crowdin rm -r ~/Downloads/crowdin
unzip -q ~/Downloads/ublock.zip -d ~/Downloads/crowdin unzip -q ~/Downloads/ublock.zip -d ~/Downloads/crowdin
cp ~/Downloads/crowdin/ar/messages.json ../src/_locales/ar/messages.json cp ~/Downloads/crowdin/ar/messages.json ./_locales/ar/messages.json
cp ~/Downloads/crowdin/cs/messages.json ../src/_locales/cs/messages.json cp ~/Downloads/crowdin/cs/messages.json ./_locales/cs/messages.json
cp ~/Downloads/crowdin/da/messages.json ../src/_locales/da/messages.json cp ~/Downloads/crowdin/da/messages.json ./_locales/da/messages.json
cp ~/Downloads/crowdin/el/messages.json ../src/_locales/el/messages.json cp ~/Downloads/crowdin/el/messages.json ./_locales/el/messages.json
cp ~/Downloads/crowdin/es-ES/messages.json ../src/_locales/es/messages.json cp ~/Downloads/crowdin/es-ES/messages.json ./_locales/es/messages.json
cp ~/Downloads/crowdin/et/messages.json ../src/_locales/et/messages.json cp ~/Downloads/crowdin/et/messages.json ./_locales/et/messages.json
cp ~/Downloads/crowdin/fi/messages.json ../src/_locales/fi/messages.json cp ~/Downloads/crowdin/fi/messages.json ./_locales/fi/messages.json
cp ~/Downloads/crowdin/he/messages.json ../src/_locales/he/messages.json cp ~/Downloads/crowdin/he/messages.json ./_locales/he/messages.json
cp ~/Downloads/crowdin/hi/messages.json ../src/_locales/hi/messages.json cp ~/Downloads/crowdin/hi/messages.json ./_locales/hi/messages.json
cp ~/Downloads/crowdin/hr/messages.json ../src/_locales/hr/messages.json cp ~/Downloads/crowdin/hr/messages.json ./_locales/hr/messages.json
cp ~/Downloads/crowdin/hu/messages.json ../src/_locales/hu/messages.json cp ~/Downloads/crowdin/hu/messages.json ./_locales/hu/messages.json
cp ~/Downloads/crowdin/id/messages.json ../src/_locales/id/messages.json cp ~/Downloads/crowdin/id/messages.json ./_locales/id/messages.json
cp ~/Downloads/crowdin/it/messages.json ../src/_locales/it/messages.json cp ~/Downloads/crowdin/it/messages.json ./_locales/it/messages.json
cp ~/Downloads/crowdin/ja/messages.json ../src/_locales/ja/messages.json cp ~/Downloads/crowdin/ja/messages.json ./_locales/ja/messages.json
cp ~/Downloads/crowdin/mr/messages.json ../src/_locales/mr/messages.json cp ~/Downloads/crowdin/mr/messages.json ./_locales/mr/messages.json
cp ~/Downloads/crowdin/no/messages.json ../src/_locales/nb/messages.json cp ~/Downloads/crowdin/no/messages.json ./_locales/nb/messages.json
cp ~/Downloads/crowdin/nl/messages.json ../src/_locales/nl/messages.json cp ~/Downloads/crowdin/nl/messages.json ./_locales/nl/messages.json
cp ~/Downloads/crowdin/pl/messages.json ../src/_locales/pl/messages.json cp ~/Downloads/crowdin/pl/messages.json ./_locales/pl/messages.json
cp ~/Downloads/crowdin/pt-BR/messages.json ../src/_locales/pt_BR/messages.json cp ~/Downloads/crowdin/pt-BR/messages.json ./_locales/pt_BR/messages.json
cp ~/Downloads/crowdin/pt-PT/messages.json ../src/_locales/pt_PT/messages.json cp ~/Downloads/crowdin/pt-PT/messages.json ./_locales/pt_PT/messages.json
cp ~/Downloads/crowdin/ro/messages.json ../src/_locales/ro/messages.json cp ~/Downloads/crowdin/ro/messages.json ./_locales/ro/messages.json
cp ~/Downloads/crowdin/ru/messages.json ../src/_locales/ru/messages.json cp ~/Downloads/crowdin/ru/messages.json ./_locales/ru/messages.json
cp ~/Downloads/crowdin/sv-SE/messages.json ../src/_locales/sv/messages.json cp ~/Downloads/crowdin/sv-SE/messages.json ./_locales/sv/messages.json
cp ~/Downloads/crowdin/tr/messages.json ../src/_locales/tr/messages.json cp ~/Downloads/crowdin/tr/messages.json ./_locales/tr/messages.json
cp ~/Downloads/crowdin/uk/messages.json ../src/_locales/uk/messages.json cp ~/Downloads/crowdin/uk/messages.json ./_locales/uk/messages.json
cp ~/Downloads/crowdin/vi/messages.json ../src/_locales/vi/messages.json cp ~/Downloads/crowdin/vi/messages.json ./_locales/vi/messages.json
cp ~/Downloads/crowdin/zh-CN/messages.json ../src/_locales/zh_CN/messages.json cp ~/Downloads/crowdin/zh-CN/messages.json ./_locales/zh_CN/messages.json
# #
cp ~/Downloads/crowdin/ar/description.txt ../dist/description/description-ar.txt cp ~/Downloads/crowdin/ar/description.txt ./dist/description/description-ar.txt
cp ~/Downloads/crowdin/cs/description.txt ../dist/description/description-cs.txt cp ~/Downloads/crowdin/cs/description.txt ./dist/description/description-cs.txt
cp ~/Downloads/crowdin/da/description.txt ../dist/description/description-da.txt cp ~/Downloads/crowdin/da/description.txt ./dist/description/description-da.txt
#cp ~/Downloads/crowdin/el/description.txt ../dist/description/description-el.txt #cp ~/Downloads/crowdin/el/description.txt ./dist/description/description-el.txt
cp ~/Downloads/crowdin/es-ES/description.txt ../dist/description/description-es.txt cp ~/Downloads/crowdin/es-ES/description.txt ./dist/description/description-es.txt
cp ~/Downloads/crowdin/et/description.txt ../dist/description/description-et.txt cp ~/Downloads/crowdin/et/description.txt ./dist/description/description-et.txt
cp ~/Downloads/crowdin/fi/description.txt ../dist/description/description-fi.txt cp ~/Downloads/crowdin/fi/description.txt ./dist/description/description-fi.txt
cp ~/Downloads/crowdin/he/description.txt ../dist/description/description-he.txt cp ~/Downloads/crowdin/he/description.txt ./dist/description/description-he.txt
cp ~/Downloads/crowdin/hr/description.txt ../dist/description/description-hr.txt cp ~/Downloads/crowdin/hr/description.txt ./dist/description/description-hr.txt
cp ~/Downloads/crowdin/hu/description.txt ../dist/description/description-hu.txt cp ~/Downloads/crowdin/hu/description.txt ./dist/description/description-hu.txt
cp ~/Downloads/crowdin/id/description.txt ../dist/description/description-id.txt cp ~/Downloads/crowdin/id/description.txt ./dist/description/description-id.txt
cp ~/Downloads/crowdin/it/description.txt ../dist/description/description-it.txt cp ~/Downloads/crowdin/it/description.txt ./dist/description/description-it.txt
#cp ~/Downloads/crowdin/ja/description.txt ../dist/description/description-ja.txt #cp ~/Downloads/crowdin/ja/description.txt ./dist/description/description-ja.txt
cp ~/Downloads/crowdin/no/description.txt ../dist/description/description-no.txt cp ~/Downloads/crowdin/no/description.txt ./dist/description/description-no.txt
cp ~/Downloads/crowdin/nl/description.txt ../dist/description/description-nl.txt cp ~/Downloads/crowdin/nl/description.txt ./dist/description/description-nl.txt
cp ~/Downloads/crowdin/pl/description.txt ../dist/description/description-pl.txt cp ~/Downloads/crowdin/pl/description.txt ./dist/description/description-pl.txt
cp ~/Downloads/crowdin/pt-BR/description.txt ../dist/description/description-pt_BR.txt cp ~/Downloads/crowdin/pt-BR/description.txt ./dist/description/description-pt_BR.txt
cp ~/Downloads/crowdin/pt-PT/description.txt ../dist/description/description-pt_PT.txt cp ~/Downloads/crowdin/pt-PT/description.txt ./dist/description/description-pt_PT.txt
cp ~/Downloads/crowdin/ro/description.txt ../dist/description/description-ro.txt cp ~/Downloads/crowdin/ro/description.txt ./dist/description/description-ro.txt
cp ~/Downloads/crowdin/ru/description.txt ../dist/description/description-ru.txt cp ~/Downloads/crowdin/ru/description.txt ./dist/description/description-ru.txt
cp ~/Downloads/crowdin/sv-SE/description.txt ../dist/description/description-sv.txt cp ~/Downloads/crowdin/sv-SE/description.txt ./dist/description/description-sv.txt
cp ~/Downloads/crowdin/tr/description.txt ../dist/description/description-tr.txt cp ~/Downloads/crowdin/tr/description.txt ./dist/description/description-tr.txt
cp ~/Downloads/crowdin/uk/description.txt ../dist/description/description-uk.txt cp ~/Downloads/crowdin/uk/description.txt ./dist/description/description-uk.txt
#cp ~/Downloads/crowdin/vi/description.txt ../dist/description/description-vi.txt #cp ~/Downloads/crowdin/vi/description.txt ./dist/description/description-vi.txt
cp ~/Downloads/crowdin/zh-CN/description.txt ../dist/description/description-zh_CN.txt cp ~/Downloads/crowdin/zh-CN/description.txt ./dist/description/description-zh_CN.txt
# #

View File

@ -4,14 +4,14 @@
echo "*** uBlock: Creating web store package" echo "*** uBlock: Creating web store package"
echo "*** uBlock: Copying files" echo "*** uBlock: Copying files"
cp -R assets ../dist/ublock/ cp -R assets dist/ublock/
rm ../dist/ublock/assets/*.sh rm dist/ublock/assets/*.sh
cp -R css ../dist/ublock/ cp -R css dist/ublock/
cp -R img ../dist/ublock/ cp -R img dist/ublock/
cp -R js ../dist/ublock/ cp -R js dist/ublock/
cp -R lib ../dist/ublock/ cp -R lib dist/ublock/
cp -R _locales ../dist/ublock/ cp -R _locales dist/ublock/
cp *.html ../dist/ublock/ cp *.html dist/ublock/
cp *.txt ../dist/ublock/ cp *.txt dist/ublock/
cp manifest.json ../dist/ublock/ cp manifest.json dist/ublock/
echo "*** uBlock: Package done." echo "*** uBlock: Package done."

View File

@ -3,5 +3,5 @@
# This script assumes a linux environment # This script assumes a linux environment
echo "*** uBlock: Cleaning." echo "*** uBlock: Cleaning."
rm -R ../dist/ublock/* rm -R dist/ublock/*
echo "*** uBlock: Cleaned." echo "*** uBlock: Cleaned."

View File

@ -4,12 +4,12 @@
echo "*** uBlock: Creating web store package" echo "*** uBlock: Creating web store package"
echo "*** uBlock: Copying files" echo "*** uBlock: Copying files"
cp -R css ../dist/ublock/ cp -R css dist/ublock/
cp -R img ../dist/ublock/ cp -R img dist/ublock/
cp -R js ../dist/ublock/ cp -R js dist/ublock/
cp -R lib ../dist/ublock/ cp -R lib dist/ublock/
cp -R _locales ../dist/ublock/ cp -R _locales dist/ublock/
cp *.html ../dist/ublock/ cp *.html dist/ublock/
cp *.txt ../dist/ublock/ cp *.txt dist/ublock/
cp manifest.json ../dist/ublock/ cp manifest.json dist/ublock/
echo "*** uBlock: Package done." echo "*** uBlock: Package done."

View File

@ -4,7 +4,7 @@
echo "*** uBlock: Creating Opera web store package" echo "*** uBlock: Creating Opera web store package"
./make-chrome.sh ./make-chrome.sh
rm -r ../dist/ublock/_locales/el rm -r dist/ublock/_locales/el
rm -r ../dist/ublock/_locales/ja rm -r dist/ublock/_locales/ja
rm -r ../dist/ublock/_locales/vi rm -r dist/ublock/_locales/vi
echo "*** uBlock: Opera package done." echo "*** uBlock: Opera package done."