Hello community, here is the log from the commit of package python-buku for openSUSE:Factory checked in at 2017-09-20 17:12:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-buku (Old) and /work/SRC/openSUSE:Factory/.python-buku.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-buku" Wed Sep 20 17:12:30 2017 rev:4 rq:527319 version:3.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-buku/python-buku.changes 2017-09-12 19:55:32.225877562 +0200 +++ /work/SRC/openSUSE:Factory/.python-buku.new/python-buku.changes 2017-09-20 17:12:31.418968337 +0200 @@ -1,0 +2,11 @@ +Mon Sep 18 08:05:12 UTC 2017 - [email protected] + +- Update to version 3.4 + * Export bookmarks (including specific tags) to Buku DB file + using --export + * Option --import can merge Buku DB files now, option --merge is + retired + * Option --suggest now works at prompt as well + * Auto-import issue when Firefox is not installed fixed + +------------------------------------------------------------------- Old: ---- buku-3.3.1.tar.gz New: ---- buku-3.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-buku.spec ++++++ --- /var/tmp/diff_new_pack.AhKjv0/_old 2017-09-20 17:12:31.970890644 +0200 +++ /var/tmp/diff_new_pack.AhKjv0/_new 2017-09-20 17:12:31.970890644 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-buku -Version: 3.3.1 +Version: 3.4 Release: 0 Summary: Command-line bookmark manager License: GPL-3.0+ ++++++ buku-3.3.1.tar.gz -> buku-3.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/CHANGELOG new/buku-3.4/CHANGELOG --- old/buku-3.3.1/CHANGELOG 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/CHANGELOG 2017-09-18 09:53:49.000000000 +0200 @@ -1,3 +1,14 @@ +Buku 3.4 +2017-09-18 + +What's in? +- Export bookmarks (including specific tags) to Buku DB file using `--export` +- Option `--import` can merge Buku DB files now, option `--merge` is retired +- Option `--suggest` now works at prompt as well +- Auto-import issue when Firefox is not installed fixed + +------------------------------------------------------------------------------- + Buku 3.3.1 2017-09-11 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/PKG-INFO new/buku-3.4/PKG-INFO --- old/buku-3.3.1/PKG-INFO 2017-09-11 07:37:02.000000000 +0200 +++ new/buku-3.4/PKG-INFO 2017-09-18 09:54:17.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: buku -Version: 3.3.1 +Version: 3.4 Summary: Powerful command-line bookmark manager. Home-page: https://github.com/jarun/Buku Author: Arun Prakash Jana Author-email: [email protected] License: GPLv3 +Description-Content-Type: UNKNOWN Description: <h1 align="center">Buku</h1> <p align="center"> @@ -21,7 +22,7 @@ </p> <p align="center"> - <a href="https://asciinema.org/a/137065"><img src="https://asciinema.org/a/137065.png" alt="Buku in action!" width="734"/></a> + <a href="https://asciinema.org/a/137065"><img src="https://s26.postimg.org/o6lka0dw9/buku_demo.png" alt="Buku in action!" width="734"/></a> </p> <p align="center"><i>Buku in action!</i></p> @@ -196,24 +197,23 @@ search bookmarks by tags use ',' to find entries matching ANY tag use '+' to find entries matching ALL tags - excludes entries matching tags following ' - ' + excludes entries with tags after ' - ' list all tags, if no search keywords ENCRYPTION OPTIONS: - -l, --lock [N] encrypt DB file with N (> 0, default 8) - hash iterations to generate key - -k, --unlock [N] decrypt DB file with N (> 0, default 8) - hash iterations to generate key + -l, --lock [N] encrypt DB in N (default 8) # iterations + -k, --unlock [N] decrypt DB in N (default 8) # iterations POWER TOYS: --ai auto-import from Firefox and Chrome -e, --export file export bookmarks in Firefox format html export markdown, if file ends with '.md' format: [title](url), 1 entry per line - use --tag to export only specific tags + export buku DB, if file ends with '.db' + use --tag to export specific tags -i, --import file import Firefox or Chrome bookmarks html import markdown, if file ends with '.md' - -m, --merge file add bookmarks from another buku DB file + import buku DB, if file ends with '.db' -p, --print [...] show record details by indices, ranges print all bookmarks, if no arguments -n shows the last n results (like tail) @@ -308,11 +308,13 @@ $ buku -e bookmarks.html --tag tag 1, tag 2 $ buku -e bookmarks.md --tag tag 1, tag 2 + $ buku -e bookmarks.db --tag tag 1, tag 2 All bookmarks are exported if --tag is not specified. 10. **Import** bookmarks from HTML and markdown: $ buku -i bookmarks.html $ buku -i bookmarks.md + $ buku -i bookmarks.db 11. **Delete only comment** for bookmark at 15012014: $ buku -u 15012014 -c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/README.md new/buku-3.4/README.md --- old/buku-3.3.1/README.md 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/README.md 2017-09-18 09:53:49.000000000 +0200 @@ -13,7 +13,7 @@ </p> <p align="center"> -<a href="https://asciinema.org/a/137065"><img src="https://asciinema.org/a/137065.png" alt="Buku in action!" width="734"/></a> +<a href="https://asciinema.org/a/137065"><img src="https://s26.postimg.org/o6lka0dw9/buku_demo.png" alt="Buku in action!" width="734"/></a> </p> <p align="center"><i>Buku in action!</i></p> @@ -188,24 +188,23 @@ search bookmarks by tags use ',' to find entries matching ANY tag use '+' to find entries matching ALL tags - excludes entries matching tags following ' - ' + excludes entries with tags after ' - ' list all tags, if no search keywords ENCRYPTION OPTIONS: - -l, --lock [N] encrypt DB file with N (> 0, default 8) - hash iterations to generate key - -k, --unlock [N] decrypt DB file with N (> 0, default 8) - hash iterations to generate key + -l, --lock [N] encrypt DB in N (default 8) # iterations + -k, --unlock [N] decrypt DB in N (default 8) # iterations POWER TOYS: --ai auto-import from Firefox and Chrome -e, --export file export bookmarks in Firefox format html export markdown, if file ends with '.md' format: [title](url), 1 entry per line - use --tag to export only specific tags + export buku DB, if file ends with '.db' + use --tag to export specific tags -i, --import file import Firefox or Chrome bookmarks html import markdown, if file ends with '.md' - -m, --merge file add bookmarks from another buku DB file + import buku DB, if file ends with '.db' -p, --print [...] show record details by indices, ranges print all bookmarks, if no arguments -n shows the last n results (like tail) @@ -300,11 +299,13 @@ $ buku -e bookmarks.html --tag tag 1, tag 2 $ buku -e bookmarks.md --tag tag 1, tag 2 + $ buku -e bookmarks.db --tag tag 1, tag 2 All bookmarks are exported if --tag is not specified. 10. **Import** bookmarks from HTML and markdown: $ buku -i bookmarks.html $ buku -i bookmarks.md + $ buku -i bookmarks.db 11. **Delete only comment** for bookmark at 15012014: $ buku -u 15012014 -c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/auto-completion/bash/buku-completion.bash new/buku-3.4/auto-completion/bash/buku-completion.bash --- old/buku-3.3.1/auto-completion/bash/buku-completion.bash 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/auto-completion/bash/buku-completion.bash 2017-09-18 09:53:49.000000000 +0200 @@ -26,7 +26,6 @@ -j --json -k --unlock -l --lock - -m --merge --nc --np -o --open @@ -58,7 +57,6 @@ -f --format -i --import --immutable - -m --merge -r --sreg --replace -s --sany diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/auto-completion/fish/buku.fish new/buku-3.4/auto-completion/fish/buku.fish --- old/buku-3.3.1/auto-completion/fish/buku.fish 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/auto-completion/fish/buku.fish 2017-09-18 09:53:49.000000000 +0200 @@ -19,7 +19,6 @@ complete -c buku -s j -l json --description 'show Json output for print and search' complete -c buku -s k -l unlock --description 'decrypt database' complete -c buku -s l -l lock --description 'encrypt database' -complete -c buku -s m -l merge -r --description 'merge another buku database' complete -c buku -l nc --description 'disable color output' complete -c buku -l np --description 'non-interactive mode' complete -c buku -s o -l open --description 'open bookmarks in browser' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/auto-completion/zsh/_buku new/buku-3.4/auto-completion/zsh/_buku --- old/buku-3.3.1/auto-completion/zsh/_buku 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/auto-completion/zsh/_buku 2017-09-18 09:53:49.000000000 +0200 @@ -15,16 +15,15 @@ '(--colors)--colors[set output colors in 5-letter string]:color string' '(-d --delete)'{-d,--delete}'[delete bookmark]' '(--deep)--deep[search matching substrings]' - '(-e --export)'{-e,--export}'[export bookmarks]:html output file' + '(-e --export)'{-e,--export}'[export bookmarks]:html/md/db output file' '(--expand)--expand[expand a tny.im shortened URL]:index/shorturl' '(-f --format)'{-f,--format}'[limit fields in print and Json output]:value' '(-h --help)'{-h,--help}'[show help]' - '(-i --import)'{-i,--import}'[import bookmarks]:html imput file' + '(-i --import)'{-i,--import}'[import bookmarks]:html/md/db input file' '(--immutable)--immutable[disable title update from web]:value' '(-j --json)'{-j,--json}'[show Json output for print and search]' '(-k --unlock)'{-k,--unlock}'[decrypt database]' '(-l --lock)'{-l,--lock}'[encrypt database]' - '(-m --merge)'{-m,--merge}'[merge another buku database]:buku db file' '(--nc)--nc[disable color output]' '(--np)--np[noninteractive mode]' '(-o --open)'{-o,--open}'[open bookmarks in browser]' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/buku.1 new/buku-3.4/buku.1 --- old/buku-3.3.1/buku.1 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/buku.1 2017-09-18 09:53:49.000000000 +0200 @@ -1,4 +1,4 @@ -.TH "BUKU" "1" "Sep 2017" "Version 3.3.1" "User Commands" +.TH "BUKU" "1" "Sep 2017" "Version 3.4" "User Commands" .SH NAME buku \- Powerful command-line bookmark manager. .SH SYNOPSIS @@ -77,7 +77,7 @@ - Auto-import looks in the default installation path and default user profile. - URLs starting with `place:`, `file://` and `apt:` are ignored during import. - Folder names are automatically imported as tags if --tacit is used. - - An auto-generated tag in the format 'YYYYMonDD' is added if --tacit is not used. + - An auto-generated tag in the format 'YYYYMonDD' is added if --tacit is not used in html or markdown import. .PP .IP 10. 4 \fBEncryption\fR is optional and manual. AES256 algorithm is used. To use encryption, the database file should be unlocked (-k) before using \fBbuku\fR and locked (-l) afterwards. Between these 2 operations, the database file lies unencrypted on the disk, and NOT in memory. Also, note that the database file is \fBunencrypted on creation\fR. @@ -188,15 +188,14 @@ .I file has extension '.md'. .br -Markdown format: [title](url), 1 entry per line. +Markdown format: [title](url), 1 entry per line. A buku database is generated if +.I file +has extension '.db'. .TP .BI \-i " " \--import " file" Import bookmarks exported from Firefox or Google Chrome as HTML. .I file -is considered Markdown (compliant with --export format) if it has '.md' extension. -.TP -.BI \-m " " \--merge " file" -Add bookmarks from another buku database file. +is considered Markdown (compliant with --export format) if it has '.md' extension or another buku database if the extension is '.db'. .TP .BI \-p " " \--print " [...]" Show details (DB index, URL, title, tags and comment) of bookmark record by DB index. If no arguments, all records with actual index from DB are shown. Accepts hyphenated ranges and space-separated indices. A negative value (introduced for convenience) behaves like the tail utility, e.g., -n shows the details of the last n bookmarks. @@ -504,6 +503,8 @@ .B buku -e bookmarks.html --tag tag 1, tag 2 .br .B buku -e bookmarks.md --tag tag 1, tag 2 +.br +.B buku -e bookmarks.db --tag tag 1, tag 2 .EE .PP .IP "" 4 @@ -517,6 +518,8 @@ .B buku -i bookmarks.html .br .B buku -i bookmarks.md +.br +.B buku -i bookmarks.db .EE .PP .IP 11. 4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/buku.egg-info/PKG-INFO new/buku-3.4/buku.egg-info/PKG-INFO --- old/buku-3.3.1/buku.egg-info/PKG-INFO 2017-09-11 07:37:02.000000000 +0200 +++ new/buku-3.4/buku.egg-info/PKG-INFO 2017-09-18 09:54:17.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: buku -Version: 3.3.1 +Version: 3.4 Summary: Powerful command-line bookmark manager. Home-page: https://github.com/jarun/Buku Author: Arun Prakash Jana Author-email: [email protected] License: GPLv3 +Description-Content-Type: UNKNOWN Description: <h1 align="center">Buku</h1> <p align="center"> @@ -21,7 +22,7 @@ </p> <p align="center"> - <a href="https://asciinema.org/a/137065"><img src="https://asciinema.org/a/137065.png" alt="Buku in action!" width="734"/></a> + <a href="https://asciinema.org/a/137065"><img src="https://s26.postimg.org/o6lka0dw9/buku_demo.png" alt="Buku in action!" width="734"/></a> </p> <p align="center"><i>Buku in action!</i></p> @@ -196,24 +197,23 @@ search bookmarks by tags use ',' to find entries matching ANY tag use '+' to find entries matching ALL tags - excludes entries matching tags following ' - ' + excludes entries with tags after ' - ' list all tags, if no search keywords ENCRYPTION OPTIONS: - -l, --lock [N] encrypt DB file with N (> 0, default 8) - hash iterations to generate key - -k, --unlock [N] decrypt DB file with N (> 0, default 8) - hash iterations to generate key + -l, --lock [N] encrypt DB in N (default 8) # iterations + -k, --unlock [N] decrypt DB in N (default 8) # iterations POWER TOYS: --ai auto-import from Firefox and Chrome -e, --export file export bookmarks in Firefox format html export markdown, if file ends with '.md' format: [title](url), 1 entry per line - use --tag to export only specific tags + export buku DB, if file ends with '.db' + use --tag to export specific tags -i, --import file import Firefox or Chrome bookmarks html import markdown, if file ends with '.md' - -m, --merge file add bookmarks from another buku DB file + import buku DB, if file ends with '.db' -p, --print [...] show record details by indices, ranges print all bookmarks, if no arguments -n shows the last n results (like tail) @@ -308,11 +308,13 @@ $ buku -e bookmarks.html --tag tag 1, tag 2 $ buku -e bookmarks.md --tag tag 1, tag 2 + $ buku -e bookmarks.db --tag tag 1, tag 2 All bookmarks are exported if --tag is not specified. 10. **Import** bookmarks from HTML and markdown: $ buku -i bookmarks.html $ buku -i bookmarks.md + $ buku -i bookmarks.db 11. **Delete only comment** for bookmark at 15012014: $ buku -u 15012014 -c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/buku-3.3.1/buku.py new/buku-3.4/buku.py --- old/buku-3.3.1/buku.py 2017-09-11 07:36:37.000000000 +0200 +++ new/buku-3.4/buku.py 2017-09-18 09:53:49.000000000 +0200 @@ -39,7 +39,7 @@ from urllib3.util import parse_url, make_headers import webbrowser -__version__ = '3.3.1' +__version__ = '3.4' __author__ = 'Arun Prakash Jana <[email protected]>' __license__ = 'GPLv3' @@ -147,17 +147,17 @@ @staticmethod def get_filehash(filepath): - """Get the SHA256 hash of a file + """Get the SHA256 hash of a file. Parameters ---------- filepath : str - Path to the file + Path to the file. Returns ------- hash : bytes - Hash digest of file + Hash digest of file. """ from hashlib import sha256 @@ -173,14 +173,14 @@ @staticmethod def encrypt_file(iterations, dbfile=None): - """Encrypt the bookmarks database file + """Encrypt the bookmarks database file. Parameters ---------- iterations : int - Number of iterations for key generation + Number of iterations for key generation. dbfile : str, optional - Custom database file path (including filename) + Custom database file path (including filename). """ try: @@ -271,14 +271,14 @@ @staticmethod def decrypt_file(iterations, dbfile=None): - """Decrypt the bookmarks database file + """Decrypt the bookmarks database file. Parameters ---------- iterations : int - Number of iterations for key generation + Number of iterations for key generation. dbfile : str, optional - Custom database file path (including filename) + Custom database file path (including filename). The '.enc' suffix must be omitted. """ @@ -370,19 +370,19 @@ def import_md(filepath, newtag): - """Parse bookmark markdown file + """Parse bookmark markdown file. Parameters ---------- filepath : str - Path to markdown file + Path to markdown file. newtag : str - New tag for bookmarks in markdown file + New tag for bookmarks in markdown file. Returns ------- tuple - Parsed result + Parsed result. """ with open(filepath, mode='r', encoding='utf-8') as infp: for line in infp: @@ -410,21 +410,21 @@ def import_html(html_soup, add_parent_folder_as_tag, newtag): - """Parse bookmark html + """Parse bookmark html. Parameters ---------- html_soup : BeautifulSoup object - BeautifulSoup representation of bookmark html + BeautifulSoup representation of bookmark html. add_parent_folder_as_tag : bool - True if bookmark parent folders should be added as tags else False + True if bookmark parent folders should be added as tags else False. newtag : str - A new unique tag to add to imported bookmarks + A new unique tag to add to imported bookmarks. Returns ------- tuple - Parsed result + Parsed result. """ # compatibility @@ -472,14 +472,14 @@ class BukuDb: - """Abstracts all database operations + """Abstracts all database operations. Attributes ---------- - conn : sqlite database connection - cur : sqlite database cursor + conn : sqlite database connection. + cur : sqlite database cursor. json : bool - True if results should be printed in json format else False + True if results should be printed in json format else False. field_filter : int Indicates format for displaying bookmarks. Default is 0. chatty : bool @@ -487,12 +487,12 @@ """ def __init__(self, json=False, field_filter=0, chatty=False, dbfile=None, colorize=True): - """Database initialization API + """Database initialization API. Parameters ---------- json : bool, optional - True if results should be printed in json format else False + True if results should be printed in json format else False. field_filter : int, optional Indicates format for displaying bookmarks. Default is 0. chatty : bool, optional @@ -501,25 +501,25 @@ Indicates whether color should be used in output. Default is True. """ - self.conn, self.cur = BukuDb.initdb(dbfile) self.json = json self.field_filter = field_filter self.chatty = chatty self.colorize = colorize + self.conn, self.cur = BukuDb.initdb(dbfile, self.chatty) @staticmethod def get_default_dbdir(): - """Determine the directory path where dbfile will be stored + """Determine the directory path where dbfile will be stored. If the platform is Windows, use %APPDATA% else if $XDG_DATA_HOME is defined, use it else if $HOME exists, use it - else use the current directory + else use the current directory. Returns ------- str - Path to database file + Path to database file. """ data_home = os.environ.get('XDG_DATA_HOME') @@ -537,7 +537,7 @@ return os.path.join(data_home, 'buku') @staticmethod - def initdb(dbfile=None): + def initdb(dbfile=None, chatty=False): """Initialize the database connection. Create DB file and/or bookmarks table if they don't exist. @@ -546,12 +546,14 @@ Parameters ---------- dbfile : str, optional - Custom database file path (including filename) + Custom database file path (including filename). + chatty : bool + If True, shows informative message on DB creation. Returns ------- tuple - (connection, cursor) + (connection, cursor). """ if not dbfile: @@ -580,7 +582,7 @@ elif db_exists and enc_exists: logerr('Both encrypted and flat DB files exist!') sys.exit(1) - else: + elif chatty: # not db_exists and not enc_exists print('DB file is being created at %s.\nYou should encrypt it.' % dbfile) @@ -609,12 +611,12 @@ return (conn, cur) def get_rec_all(self): - """Get all the bookmarks in the database + """Get all the bookmarks in the database. Returns ------- list - A list of tuples representing bookmark records + A list of tuples representing bookmark records. """ self.cur.execute('SELECT * FROM bookmarks') @@ -626,12 +628,12 @@ Parameters ---------- index : int - DB index of bookmark record + DB index of bookmark record. Returns ------- tuple or None - Bookmark data, or None if index is not found + Bookmark data, or None if index is not found. """ self.cur.execute('SELECT * FROM bookmarks WHERE id = ? LIMIT 1', (index,)) @@ -639,17 +641,17 @@ return resultset[0] if resultset else None def get_rec_id(self, url): - """Check if URL already exists in DB + """Check if URL already exists in DB. Parameters ---------- url : str - A URL to search for in the DB + A URL to search for in the DB. Returns ------- int - DB index, or -1 if URL not found in DB + DB index, or -1 if URL not found in DB. """ self.cur.execute('SELECT id FROM bookmarks WHERE URL = ? LIMIT 1', (url,)) @@ -657,12 +659,12 @@ return resultset[0][0] if resultset else -1 def get_max_id(self): - """Fetch the ID of the last record + """Fetch the ID of the last record. Returns ------- int - ID of the record if any record exists, else -1 + ID of the record if any record exists, else -1. """ self.cur.execute('SELECT MAX(id) from bookmarks') @@ -670,12 +672,12 @@ return -1 if resultset[0][0] is None else resultset[0][0] def add_rec(self, url, title_in=None, tags_in=None, desc=None, immutable=0, delay_commit=False): - """Add a new bookmark + """Add a new bookmark. Parameters ---------- url : str - URL to bookmark + URL to bookmark. title_in :str, optional Title to add manually. Default is None. tags_in : str, optional @@ -693,7 +695,7 @@ Returns ------- int - DB index of new bookmark on success, -1 on failure + DB index of new bookmark on success, -1 on failure. """ # Return error for empty URL @@ -750,14 +752,14 @@ return -1 def append_tag_at_index(self, index, tags_in, delay_commit=False): - """Append tags to bookmark tagset at index + """Append tags to bookmark tagset at index. Parameters ---------- index : int DB index of the record. 0 indicates all records. tags_in : str - Comma-separated tags to add manually + Comma-separated tags to add manually. delay_commit : bool, optional True if record should not be committed to the DB, leaving commit responsibility to caller. Default is False. @@ -765,7 +767,7 @@ Returns ------- bool - True on success, False on failuree + True on success, False on failure. """ if index == 0: @@ -795,14 +797,14 @@ return True def delete_tag_at_index(self, index, tags_in, delay_commit=False): - """Delete tags from bookmark tagset at index + """Delete tags from bookmark tagset at index. Parameters ---------- index : int DB index of bookmark record. 0 indicates all records. tags_in : str - Comma-separated tags to delete manually + Comma-separated tags to delete manually. delay_commit : bool, optional True if record should not be committed to the DB, leaving commit responsibility to caller. Default is False. @@ -810,7 +812,7 @@ Returns ------- bool - True on success, False on failure + True on success, False on failure. """ tags_to_delete = tags_in.strip(DELIM).split(DELIM) @@ -860,7 +862,7 @@ return True def update_rec(self, index, url=None, title_in=None, tags_in=None, desc=None, immutable=-1, threads=4): - """Update an existing record at index + """Update an existing record at index. Update all records if index is 0 and url is not specified. URL is an exception because URLs are unique in DB. @@ -870,15 +872,15 @@ index : int DB index of record. 0 indicates all records. url : str, optional - Bookmark address + Bookmark address. title_in : str, optional Title to add manually. tags_in : str, optional Comma-separated tags to add manually. Must start and end with comma. Prefix with '+,' to append to current tags. - Prefix with '-,' to delete from current tags + Prefix with '-,' to delete from current tags. desc : str, optional - Description of bookmark + Description of bookmark. immutable : int, optional Diable title fetch from web if 1. Default is -1. threads : int, optional @@ -887,7 +889,7 @@ Returns ------- bool - True on success, False on Failure + True on success, False on Failure. """ arguments = [] @@ -1077,13 +1079,13 @@ cond.acquire() def refresh(count, cond): - """Inner function to fetch titles and update records + """Inner function to fetch titles and update records. Parameters ---------- count : int Dummy input to adhere to convention. - cond : threading condition object + cond : threading condition object. """ count = 0 @@ -1153,19 +1155,19 @@ return True def edit_update_rec(self, index, immutable=-1): - """Edit in editor and update a record + """Edit in editor and update a record. Parameters ---------- index : int - DB index of the record + DB index of the record. immutable : int, optional Diable title fetch from web if 1. Default is -1. Returns ------- bool - True if updated, else False + True if updated, else False. """ editor = get_system_editor() @@ -1189,12 +1191,12 @@ return False def searchdb(self, keywords, all_keywords=False, deep=False, regex=False): - """Search DB for entries where tags, URL, or title fields match keywords + """Search DB for entries where tags, URL, or title fields match keywords. Parameters ---------- keywords : list of str - Keywords to search + Keywords to search. all_keywords : bool, optional True to return records matching ALL keywords. False (default value) to return records matching ANY keyword. @@ -1206,7 +1208,7 @@ Returns ------- list or None - List of search results, or None if no matches + List of search results, or None if no matches. """ if not keywords: return None @@ -1271,7 +1273,7 @@ return self.cur.fetchall() def search_by_tag(self, tags): - """Search bookmarks for entries with given tags + """Search bookmarks for entries with given tags. Parameters ---------- @@ -1285,7 +1287,7 @@ Returns ------- list or None - List of search results, or None if no matches + List of search results, or None if no matches. """ # do not allow combination of search logics @@ -1316,7 +1318,7 @@ Parameters ---------- index : int - DB index of deleted entry + DB index of deleted entry. delay_commit : bool, optional True if record should not be committed to the DB, leaving commit responsibility to caller. Default is False. @@ -1343,7 +1345,7 @@ print('Index %d moved to %d' % (row[0], index)) def delete_rec(self, index, low=0, high=0, is_range=False, delay_commit=False): - """Delete a single record or remove the table if index is None + """Delete a single record or remove the table if index is None. Parameters ---------- @@ -1434,7 +1436,7 @@ Returns ------- bool - True on success, False on failure + True on success, False on failure. """ resp = read_in('Delete the search results? (y/n): ') if resp != 'y': @@ -1455,7 +1457,7 @@ return True def delete_rec_all(self, delay_commit=False): - """Removes all records in the Bookmarks table + """Removes all records in the Bookmarks table. Parameters ---------- @@ -1466,7 +1468,7 @@ Returns ------- bool - True on success, False on failure + True on success, False on failure. """ try: @@ -1479,12 +1481,12 @@ return False def cleardb(self): - """Drops the bookmark table if it exists + """Drops the bookmark table if it exists. Returns ------- bool - True on success, False on failure + True on success, False on failure. """ resp = read_in('Remove ALL bookmarks? (y/n): ') @@ -1498,9 +1500,9 @@ return True def print_rec(self, index=0, low=0, high=0, is_range=False): - """Print bookmark details at index or all bookmarks if index is 0 + """Print bookmark details at index or all bookmarks if index is 0. - A negative index behaves like tail, if title is blank show "Untitled" + A negative index behaves like tail, if title is blank show "Untitled". Parameters ----------- @@ -1602,13 +1604,13 @@ print(format_json(resultset, field_filter=self.field_filter)) def get_tag_all(self): - """Get list of tags in DB + """Get list of tags in DB. Returns ------- tuple (list of unique tags sorted alphabetically, - dictionary of {tag: usage_count}) + dictionary of {tag: usage_count}). """ tags = [] @@ -1635,7 +1637,7 @@ return unique_tags, dic def suggest_similar_tag(self, tagstr): - """Show list of tags those go together in DB + """Show list of tags those go together in DB. Parameters ---------- @@ -1645,7 +1647,7 @@ Returns ------- str - DELIM separated string of tags + DELIM separated string of tags. """ tags = tagstr.split(',') @@ -1846,7 +1848,7 @@ return update_count def browse_by_index(self, index=0, low=0, high=0, is_range=False): - """Open URL at index or range of indies in browser + """Open URL at index or range of indies in browser. Parameters ---------- @@ -1918,6 +1920,8 @@ def exportdb(self, filepath, taglist=None): """Export DB bookmarks to file. + If destination file name ends with '.db', bookmarks are + exported to a Buku database file. If destination file name ends with '.md', bookmarks are exported to a markdown file. Otherwise, bookmarks are exported to a Firefox bookmarks.html formatted file. @@ -1966,7 +1970,7 @@ self.cur.execute(query, arguments) resultset = self.cur.fetchall() if not resultset: - print('No bookmarks exported') + print('No records found') return False if os.path.exists(filepath): @@ -1974,6 +1978,19 @@ if resp != 'y': return False + if filepath.endswith('.db'): + os.remove(filepath) + + if filepath.endswith('.db'): + outdb = BukuDb(dbfile=filepath) + qry = 'INSERT INTO bookmarks(URL, metadata, tags, desc, flags) VALUES (?, ?, ?, ?, ?)' + for row in resultset: + outdb.cur.execute(qry, (row[1], row[2], row[3], row[4], row[5])) + + outdb.conn.commit() + outdb.close() + return True + try: outfp = open(filepath, mode='w', encoding='utf-8') except Exception as e: @@ -1981,7 +1998,6 @@ return False if filepath.endswith('.md'): - outfp.write('List of buku bookmarks:\n\n') for row in resultset: if row[2] == '': out = '- [Untitled](' + row[1] + ')\n' @@ -2150,25 +2166,30 @@ True on success, False on failure. """ + FF_BM_DB_PATH = None + if sys.platform.startswith('linux'): GC_BM_DB_PATH = '~/.config/google-chrome/Default/Bookmarks' DEFAULT_FF_FOLDER = os.path.expanduser('~/.mozilla/firefox') profile = get_firefox_profile_name(DEFAULT_FF_FOLDER) - FF_BM_DB_PATH = '~/.mozilla/firefox/{}.default/places.sqlite'.format(profile) + if profile: + FF_BM_DB_PATH = '~/.mozilla/firefox/{}.default/places.sqlite'.format(profile) elif sys.platform == 'darwin': GC_BM_DB_PATH = '~/Library/Application Support/Google/Chrome/Default/Bookmarks' DEFAULT_FF_FOLDER = os.path.expanduser('~/Library/Application Support/Firefox') profile = get_firefox_profile_name(DEFAULT_FF_FOLDER) - FF_BM_DB_PATH = '~/Library/Application Support/Firefox/{}.default/places.sqlite'.format(profile) + if profile: + FF_BM_DB_PATH = '~/Library/Application Support/Firefox/{}.default/places.sqlite'.format(profile) elif sys.platform == 'win32': username = os.getlogin() GC_BM_DB_PATH = 'C:/Users/{}/AppData/Local/Google/Chrome/User Data/Default/Bookmarks'.format(username) DEFAULT_FF_FOLDER = 'C:/Users/{}/AppData/Roaming/Mozilla/Firefox/Profiles'.format(username) profile = get_firefox_profile_name(DEFAULT_FF_FOLDER) - FF_BM_DB_PATH = os.path.join(DEFAULT_FF_FOLDER, '{}.default/places.sqlite'.format(profile)) + if profile: + FF_BM_DB_PATH = os.path.join(DEFAULT_FF_FOLDER, '{}.default/places.sqlite'.format(profile)) else: logerr('Buku does not support {} yet'.format(sys.platform)) self.close_quit(1) @@ -2215,6 +2236,7 @@ Supports Firefox, Google Chrome, and IE exported html bookmarks. Supports markdown files with extension '.md'. + Supports importing bookmarks from another Buku database file. Parameters ---------- @@ -2232,6 +2254,9 @@ True on success, False on failure. """ + if filepath.endswith('.db'): + return self.mergedb(filepath) + if not tacit: newtag = gen_auto_tag() else: @@ -2322,7 +2347,7 @@ index : int, optional (if URL is provided) DB index of the bookmark with the URL to shorten. Default is 0. url : str, optional (if index is provided) - URL to shorten + URL to shorten. shorten : bool, optional True to shorten, False to expand. Default is False. @@ -2402,6 +2427,17 @@ if to_commit: self.conn.commit() + def close(self): + """Close a DB connection.""" + + if self.conn is not None: + try: + self.cur.close() + self.conn.close() + except Exception: + # ignore errors here, we're closing down + pass + def close_quit(self, exitval=0): """Close a DB connection and exit. @@ -2422,7 +2458,7 @@ class ExtendedArgumentParser(argparse.ArgumentParser): - """Extend classic argument parser""" + """Extend classic argument parser.""" @staticmethod def program_info(file=sys.stdout): @@ -2530,8 +2566,12 @@ Firefox profile name. """ - names = os.listdir(path) - profile = [name[:-8] for name in names if name.endswith('.default')][0] + try: + names = os.listdir(path) + profile = [name[:-8] for name in names if name.endswith('.default')][0] + except FileNotFoundError: + profile = None + return profile @@ -2601,7 +2641,7 @@ Returns ------- bool - True if URL is a nongeneric URL, False otherwise. + True if URL is a non-generic URL, False otherwise. """ ignored_prefix = ['place:', 'file://', 'apt:'] @@ -2721,7 +2761,7 @@ Returns ------- tuple - (title, recognized mime, bad url) + (title, recognized mime, bad url). """ page_title = None @@ -2855,7 +2895,7 @@ tuple (list of formatted tags to search, a string indicating query search operator (either OR or AND), - a regex string of tags or None if ' - ' delimiter not in tags) + a regex string of tags or None if ' - ' delimiter not in tags). """ excluded_tags = None @@ -2883,7 +2923,7 @@ Returns ------- str - New tag as YYYYMonDD + New tag as YYYYMonDD. """ import calendar as cal @@ -2892,7 +2932,7 @@ return ('%d%s%02d' % (t.tm_year, cal.month_abbr[t.tm_mon], t.tm_mday)) -def edit_at_prompt(obj, nav): +def edit_at_prompt(obj, nav, suggest=False): """Edit and add or update a bookmark. Parameters @@ -2901,6 +2941,8 @@ A valid instance of BukuDb class. nav : str Navigation command argument passed at prompt by user. + suggest : bool, optional + If True, suggest similar tags on new bookmark addition. """ if nav == 'w': @@ -2916,6 +2958,8 @@ result = edit_rec(editor, '', None, DELIM, None) if result is not None: url, title, tags, desc = result + if suggest: + tags = obj.suggest_similar_tag(tags) obj.add_rec(url, title, tags, desc) @@ -2973,17 +3017,15 @@ new_results = True elif (nav == 'q' or nav == 'd' or nav == '?' or nav.startswith('s ') or nav.startswith('S ') or nav.startswith('r ') or - nav.startswith('t ') or nav.startswith('o ') or nav.startswith('p ') or nav.startswith('g ')): + nav.startswith('t ') or nav.startswith('o ') or nav.startswith('p ') or + nav.startswith('g ')) or nav == 'w' or nav.startswith('w '): return nav - elif nav == 'w' or nav.startswith('w '): - edit_at_prompt(obj, nav) - new_results = False else: print('Invalid input') new_results = False -def prompt(obj, results, noninteractive=False, deep=False, subprompt=False): +def prompt(obj, results, noninteractive=False, deep=False, subprompt=False, suggest=False): """Show each matching result from a search and prompt. Parameters @@ -2998,6 +3040,8 @@ Use deep search. Default is False. subprompt : bool, optional If True, jump directly to subprompt. + suggest : bool, optional + If True, suggest similar tags on edit and add bookmark. """ if not type(obj) is BukuDb: @@ -3089,7 +3133,7 @@ # Edit and add or update if nav == 'w' or nav.startswith('w '): - edit_at_prompt(obj, nav) + edit_at_prompt(obj, nav, suggest) continue # Append or overwrite tags @@ -3175,7 +3219,7 @@ def print_single_rec(row, idx=0): # NOQA """Print a single DB record. - Handles both search results and individual record + Handles both search results and individual record. Parameters ---------- @@ -3284,7 +3328,7 @@ def browse(url): - """Duplicate stdin, stdout and open URL in default browser + """Duplicate stdin, stdout and open URL in default browser. .. note:: Duplicates stdin and stdout in order to suppress showing errors on the terminal. @@ -3298,6 +3342,7 @@ ---------- suppress_browser_output : bool True if a text based browser is detected. + Must be initialized (as applicable) to use the API. """ if not parse_url(url).scheme: @@ -3404,7 +3449,7 @@ Parameters ---------- msg : str - String to pass to to input() + String to pass to to input(). """ disable_sigint_handler() @@ -3429,7 +3474,7 @@ ---------- signum : int Signal number. - frame : frame object or None + frame : frame object or None. """ global interrupted @@ -3458,13 +3503,13 @@ def get_system_editor(): - """Returns default system editor is $EDITOR is set""" + """Returns default system editor is $EDITOR is set.""" return os.environ.get('EDITOR', 'none') def is_editor_valid(editor): - """Check if the editor string is valid + """Check if the editor string is valid. Parameters ---------- @@ -3489,7 +3534,7 @@ def to_temp_file_content(url, title_in, tags_in, desc): - """Generate temporary file content string + """Generate temporary file content string. Parameters ---------- @@ -3542,7 +3587,7 @@ Parameters ---------- content : str - String of content + String of content. Returns ------- @@ -3594,7 +3639,7 @@ def edit_rec(editor, url, title_in, tags_in, desc): - """Edit a bookmark record + """Edit a bookmark record. Parameters ---------- @@ -3823,7 +3868,7 @@ search bookmarks by tags use ',' to find entries matching ANY tag use '+' to find entries matching ALL tags - excludes entries matching tags following ' - ' + excludes entries with tags after ' - ' list all tags, if no search keywords''') addarg = search_grp.add_argument addarg('-s', '--sany', action='store_true', help=HIDE) @@ -3838,10 +3883,8 @@ crypto_grp = argparser.add_argument_group( title='ENCRYPTION OPTIONS', - description=''' -l, --lock [N] encrypt DB file with N (> 0, default 8) - hash iterations to generate key - -k, --unlock [N] decrypt DB file with N (> 0, default 8) - hash iterations to generate key''') + description=''' -l, --lock [N] encrypt DB in N (default 8) # iterations + -k, --unlock [N] decrypt DB in N (default 8) # iterations''') addarg = crypto_grp.add_argument addarg('-k', '--unlock', nargs='?', type=int, const=8, help=HIDE) addarg('-l', '--lock', nargs='?', type=int, const=8, help=HIDE) @@ -3856,10 +3899,11 @@ -e, --export file export bookmarks in Firefox format html export markdown, if file ends with '.md' format: [title](url), 1 entry per line - use --tag to export only specific tags + export buku DB, if file ends with '.db' + use --tag to export specific tags -i, --import file import Firefox or Chrome bookmarks html import markdown, if file ends with '.md' - -m, --merge file add bookmarks from another buku DB file + import buku DB, if file ends with '.db' -p, --print [...] show record details by indices, ranges print all bookmarks, if no arguments -n shows the last n results (like tail) @@ -3887,7 +3931,6 @@ addarg('--ai', action='store_true', help=HIDE) addarg('-e', '--export', nargs=1, help=HIDE) addarg('-i', '--import', nargs=1, dest='importfile', help=HIDE) - addarg('-m', '--merge', nargs=1, help=HIDE) addarg('-p', '--print', nargs='*', help=HIDE) addarg('-f', '--format', type=int, default=0, choices={1, 2, 3, 4}, help=HIDE) addarg('-j', '--json', action='store_true', help=HIDE) @@ -4068,7 +4111,7 @@ search_results = bdb.search_by_tag(' '.join(args.keywords)) else: # Use sub prompt to list all tags - prompt(bdb, None, args.np, subprompt=True) + prompt(bdb, None, args.np, subprompt=True, suggest=args.suggest) elif args.keywords: search_results = bdb.searchdb(args.keywords, False, args.deep) else: @@ -4244,10 +4287,6 @@ if args.ai: bdb.auto_import_from_browser() - # Merge a database file and exit - if args.merge is not None: - bdb.mergedb(args.merge[0]) - # Open URL in browser if args.open is not None: if not args.open:
