diff --git a/docs/getting-started.rst b/docs/getting-started.rst
--- a/docs/getting-started.rst
+++ b/docs/getting-started.rst
@@ -36,43 +36,7 @@
following compression algorithm gzip (`.tar.gz`, `.tgz`), bzip2
(`.tar.bz2`) , or lzma (`.tar.lzma`)
-* prepare a metadata file (`more details <./metadata.html>`__.):
-
- - specify metadata schema/vocabulary (CodeMeta is strongly recommended)
- - specify *MUST* metadata (url, authors, software name and
- the external\_identifier)
- - add all available information under the compatible metadata term.
-
- Here is an example of an atom entry file with CodeMeta terms:
-
-.. code:: xml
-
-
-
- Je suis GPL
- swh
- je-suis-gpl
- https://forge.softwareheritage.org/source/jesuisgpl/
- 2018-01-05
- Je suis GPL is a modified version of GNU Hello whose
- sole purpose is to showcase the usage of
- Software Heritage for license compliance purposes.
- 0.1
- GNU/Linux
- stable
- C
-
-
- GNU General Public License v3.0 or later
- https://spdx.org/licenses/GPL-3.0-or-later.html
-
-
- Stefano Zacchiroli
- Maintainer
-
-
-
+* (Optional) prepare a metadata file (more details :ref:`deposit-metadata`):
Push deposit
@@ -105,13 +69,17 @@
For this, we need to provide the:
* arguments: ``--username 'name' --password 'pass'`` as credentials
-* archive's path (example: ``--archive path/to/archive-name.tgz``) :
+* archive's path (example: ``--archive path/to/archive-name.tgz``)
+* software's name (optional if a metadata filepath is specified and the
+ artifact's name is included in the metadata file).
+* author's name (optional if a metadata filepath is specified and the authors
+ are included in the metadata file). This can be specified multiple times in
+ case of multiple authors.
* (optionally) metadata file's path ``--metadata
- path/to/file.metadata.xml``. If not provided, the archive's filename
- will be used to determine the metadata file, e.g:
- ``path/to/archive-name.tgz.metadata.xml``
-* (optionally) ``--slug 'your-id'`` argument, a reference to a
- unique identifier the client uses for the software object.
+ path/to/file.metadata.xml``.
+* (optionally) ``--slug 'your-id'`` argument, a reference to a unique identifier
+ the client uses for the software object. If not provided, A UUID will be
+ generated by SWH.
You can do this with the following command:
@@ -120,6 +88,8 @@
.. code:: shell
$ swh deposit upload --username name --password secret \
+ --author "some@noone" --author "second@noone" \
+ --name 'je-suis-gpl' \
--archive je-suis-gpl.tgz
with client's external identifier (``slug``)
@@ -127,6 +97,8 @@
.. code:: shell
$ swh deposit upload --username name --password secret \
+ --author "some@noone" \
+ --name 'je-suis-gpl' \
--archive je-suis-gpl.tgz \
--slug je-suis-gpl
@@ -135,11 +107,12 @@
.. code:: shell
$ swh deposit upload --username name --password secret \
+ --author "some@noone" \
+ --name 'je-suis-gpl' \
--archive je-suis-gpl.tgz \
--collection 'second-collection'
-
You just posted a deposit to your collection on Software Heritage
@@ -195,6 +168,8 @@
for the first step. You can continue adding content or metadata while you use
the ``--partial`` argument.
+To only add one new archive to the deposit:
+
.. code:: shell
$ swh deposit upload --username name --password secret \
@@ -202,39 +177,30 @@
--deposit-id 42 \
--partial
-
-In case you want to add only one new archive without metadata:
+To only add metadata to the deposit:
.. code:: shell
$ swh deposit upload --username name --password secret \
- --archive add-foo.tar.gz \
- --archive-deposit \
+ --metadata add-foo.tar.gz.metadata.xml \
--deposit-id 42 \
--partial
-If you want to add only metadata, use:
-
+or:
.. code:: shell
$ swh deposit upload --username name --password secret \
- --metadata add-foo.tar.gz.metadata.xml \
- --metadata-deposit \
+ --name 'add-foo' --author 'someone' \
--deposit-id 42 \
--partial
+
3. Finalize deposit
~~~~~~~~~~~~~~~~~~~
-On your last addition, by not declaring it as ``--partial``, the
-deposit will be considered as completed and its status will be changed
-to ``deposited``:
-.. code:: shell
-
- $ swh deposit upload --username name --password secret \
- --metadata add-foo.tar.gz.metadata.xml \
- --metadata-deposit \
- --deposit-id 42
+On your last addition (same command as before), by not declaring it
+``--partial``, the deposit will be considered completed. Its status will be
+changed to ``deposited``
Update deposit
@@ -278,9 +244,8 @@
.. code:: shell
- $ swh deposit upload --username name --password secret \
- --deposit-id 11 \
- --status
+ $ swh deposit status --username name --password secret \
+ --deposit-id 11
.. code:: json
diff --git a/docs/metadata.rst b/docs/metadata.rst
--- a/docs/metadata.rst
+++ b/docs/metadata.rst
@@ -1,3 +1,5 @@
+.. _deposit-metadata:
+
Deposit metadata
================
@@ -21,30 +23,26 @@
-- **the url** representing the location of the source *MUST* be provided under
+- **the name** of the software deposit *MUST* be provided [atom:title,
+ codemeta:name, dcterms:title]
+
+- **the authors** of the software deposit *MUST* be provided
+
+- **the url** representing the location of the source *MAY* be provided under
the url tag. The url will be used for creating an origin object in the
archive.
.. code:: xml
- www.url-example.com
- or
www.url-example.com
- or
- www.url-example.com
-
-- **the external\_identifier** *MUST* be provided as an identifier
-
-- **the name** of the software deposit *MUST* be provided [atom:title,
- codemeta:name, dcterms:title]
-- **the authors** of the software deposit *MUST* be provided
+- **the external\_identifier** *MAY* be provided as an identifier
- **the external\_identifier** *SHOULD* match the Slug external-identifier in
the header
- **the description** of the software deposit *SHOULD* be provided
- [codemeta:description]: short or long description of the software
+ [codemeta:description]: short or long description of the software
- **the license/s** of the software
deposit *SHOULD* be provided [codemeta:license]
diff --git a/swh/deposit/cli/__init__.py b/swh/deposit/cli/__init__.py
--- a/swh/deposit/cli/__init__.py
+++ b/swh/deposit/cli/__init__.py
@@ -16,8 +16,9 @@
def deposit(ctx):
"""Deposit main command
"""
- logger.debug('deposit')
ctx.ensure_object(dict)
+ log_level = ctx.obj.get('log_level', logging.INFO)
+ logger.setLevel(log_level)
def main():
diff --git a/swh/deposit/cli/client.py b/swh/deposit/cli/client.py
--- a/swh/deposit/cli/client.py
+++ b/swh/deposit/cli/client.py
@@ -90,30 +90,66 @@
os.unlink(path)
+def _client(url, username, password):
+ """Instantiate a client to access the deposit api server
+
+ Args:
+ url (str): Deposit api server
+ username (str): User
+ password (str): User's password
+
+ """
+ client = PublicApiDepositClient({
+ 'url': url,
+ 'auth': {
+ 'username': username,
+ 'password': password
+ },
+ })
+ return client
+
+
+def _collection(client):
+ """Retrieve the client's collection
+
+ """
+ # retrieve user's collection
+ sd_content = client.service_document()
+ if 'error' in sd_content:
+ raise InputError('Service document retrieval: %s' % (
+ sd_content['error'], ))
+ collection = sd_content[
+ 'service']['workspace']['collection']['sword:name']
+ return collection
+
+
def client_command_parse_input(
username, password, archive, metadata,
archive_deposit, metadata_deposit,
collection, slug, partial, deposit_id, replace,
- url, status, name, authors):
+ url, name, authors):
"""Parse the client subcommand options and make sure the combination
is acceptable*. If not, an InputError exception is raised
explaining the issue.
By acceptable, we mean:
- - A multipart deposit (create or update) needs both an
- existing software archive and an existing metadata file
+ - A multipart deposit (create or update) requires:
+
+ - an existing software archive
+ - an existing metadata file or author(s) and name provided in
+ params
- - A binary deposit (create/update) needs an existing
- software archive
+ - A binary deposit (create/update) requires an existing software
+ archive
- - A metadata deposit (create/update) needs an existing
- metadata file
+ - A metadata deposit (create/update) requires an existing metadata
+ file or author(s) and name provided in params
- - A deposit update needs a deposit_id to be provided
+ - A deposit update requires a deposit_id
- This won't prevent all failure cases though. The remaining
- errors are already dealt with the underlying api client.
+ This will not prevent all failure cases though. The remaining
+ errors are already dealt with by the underlying api client.
Raises:
InputError explaining the issue
@@ -137,33 +173,17 @@
cleanup_tempfile = False
try:
- if status and not deposit_id:
- raise InputError("Deposit id must be provided for status check")
-
- if status and deposit_id: # status is higher priority over deposit
- archive_deposit = False
- metadata_deposit = False
- archive = None
- metadata = None
-
if archive_deposit and metadata_deposit:
# too many flags use, remove redundant ones (-> multipart deposit)
archive_deposit = False
metadata_deposit = False
- if archive and not os.path.exists(archive):
- raise InputError('Software Archive %s must exist!' % archive)
-
if not slug: # generate one as this is mandatory
slug = generate_slug()
- if archive and not metadata: # we need to have the metadata
- if name and authors:
- metadata = generate_metadata_file(name, slug, authors)
- cleanup_tempfile = True
- else:
- raise InputError('Either metadata deposit file or (`--name` '
- ' and `--author`) fields must be provided')
+ if not metadata and name and authors:
+ metadata = generate_metadata_file(name, slug, authors)
+ cleanup_tempfile = True
if metadata_deposit:
archive = None
@@ -173,38 +193,22 @@
if metadata_deposit and not metadata:
raise InputError(
- "Metadata deposit filepath must be provided for metadata "
- "deposit")
-
- if metadata and not os.path.exists(metadata):
- raise InputError('Software Archive metadata %s must exist!' % (
- metadata, ))
+ "Metadata deposit must be provided for metadata "
+ "deposit (either a filepath or --name and --author)")
- if not status and not archive and not metadata:
+ if not archive and not metadata:
raise InputError(
'Please provide an actionable command. See --help for more '
- 'information.')
+ 'information')
if replace and not deposit_id:
raise InputError(
'To update an existing deposit, you must provide its id')
- client = PublicApiDepositClient({
- 'url': url,
- 'auth': {
- 'username': username,
- 'password': password
- },
- })
+ client = _client(url, username, password)
if not collection:
- # retrieve user's collection
- sd_content = client.service_document()
- if 'error' in sd_content:
- raise InputError('Service document retrieval: %s' % (
- sd_content['error'], ))
- collection = sd_content[
- 'service']['workspace']['collection']['sword:name']
+ collection = _collection(client)
return {
'archive': archive,
@@ -233,14 +237,6 @@
return {k: v for k, v in d.items() if k in keys}
-def deposit_status(config, logger):
- logger.debug('Status deposit')
- keys = ('collection', 'deposit_id')
- client = config['client']
- return client.deposit_status(
- **_subdict(config, keys))
-
-
def deposit_create(config, logger):
"""Delegate the actual deposit to the deposit client.
@@ -271,9 +267,9 @@
help="(Mandatory) User's name")
@click.option('--password', required=1,
help="(Mandatory) User's associated password")
-@click.option('--archive',
+@click.option('--archive', type=click.Path(exists=True),
help='(Optional) Software archive to deposit')
-@click.option('--metadata',
+@click.option('--metadata', type=click.Path(exists=True),
help="(Optional) Path to xml metadata file. If not provided, this will use a file named .metadata.xml") # noqa
@click.option('--archive-deposit/--no-archive-deposit', default=False,
help='(Optional) Software archive only deposit')
@@ -291,8 +287,6 @@
help='(Optional) Update by replacing existing metadata to a deposit') # noqa
@click.option('--url', default='https://deposit.softwareheritage.org/1',
help="(Optional) Deposit server api endpoint. By default, https://deposit.softwareheritage.org/1") # noqa
-@click.option('--status/--no-status', default=False,
- help="(Optional) Deposit's status")
@click.option('--verbose/--no-verbose', default=False,
help='Verbose mode')
@click.option('--name',
@@ -305,13 +299,12 @@
username, password, archive=None, metadata=None,
archive_deposit=False, metadata_deposit=False,
collection=None, slug=None, partial=False, deposit_id=None,
- replace=False, status=False,
+ replace=False,
url='https://deposit.softwareheritage.org/1',
verbose=False, name=None, author=None):
"""Software Heritage Public Deposit Client
- Create/Update deposit through the command line or access its
- status.
+ Create/Update deposit through the command line.
More documentation can be found at
https://docs.softwareheritage.org/devel/swh-deposit/getting-started.html.
@@ -324,7 +317,7 @@
config = client_command_parse_input(
username, password, archive, metadata, archive_deposit,
metadata_deposit, collection, slug, partial, deposit_id,
- replace, url, status, name, author)
+ replace, url, name, author)
except InputError as e:
msg = 'Problem during parsing options: %s' % e
r = {
@@ -340,14 +333,45 @@
deposit_id = config['deposit_id']
- if status and deposit_id:
- r = deposit_status(config, logger)
- elif not status and deposit_id:
+ if deposit_id:
r = deposit_update(config, logger)
- elif not status and not deposit_id:
+ else:
r = deposit_create(config, logger)
logger.info(r)
finally:
_cleanup_tempfile(config)
+
+
+@deposit.command()
+@click.option('--url', default='https://deposit.softwareheritage.org/1',
+ help="(Optional) Deposit server api endpoint. By default, "
+ "https://deposit.softwareheritage.org/1")
+@click.option('--username', required=1,
+ help="(Mandatory) User's name")
+@click.option('--password', required=1,
+ help="(Mandatory) User's associated password")
+@click.option('--deposit-id', default=None,
+ required=1,
+ help="Deposit identifier.")
+@click.pass_context
+def status(ctx, url, username, password, deposit_id):
+ """Deposit's status
+
+ """
+ logger.debug('Status deposit')
+ try:
+ client = _client(url, username, password)
+ collection = _collection(client)
+ except InputError as e:
+ msg = 'Problem during parsing options: %s' % e
+ r = {
+ 'error': msg,
+ }
+ logger.info(r)
+ return 1
+
+ r = client.deposit_status(
+ collection=collection, deposit_id=deposit_id)
+ logger.info(r)
diff --git a/swh/deposit/client/__init__.py b/swh/deposit/client/__init__.py
--- a/swh/deposit/client/__init__.py
+++ b/swh/deposit/client/__init__.py
@@ -38,6 +38,8 @@
data = xmltodict.parse(stream, encoding=encoding, process_namespaces=False)
if 'entry' in data:
data = data['entry']
+ if 'sword:error' in data:
+ data = data['sword:error']
return dict(data)
@@ -253,7 +255,8 @@
'detail': Some more detail about the error if any
"""
- return _parse_with_filter(xml_content, keys=['summary', 'detail'])
+ return _parse_with_filter(xml_content, keys=[
+ 'summary', 'detail', 'sword:verboseDescription'])
def do_execute(self, method, url, info):
"""Execute the http query to url using method and info information.