Skip to content

Commit

Permalink
Merge branch 'release/0.12.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
lasote committed Sep 13, 2016
2 parents 1e8886d + 9c4c44f commit 54a9817
Show file tree
Hide file tree
Showing 66 changed files with 1,705 additions and 932 deletions.
2 changes: 1 addition & 1 deletion conans/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
from conans.util.files import load
import os

__version__ = '0.11.1'
__version__ = '0.12.0'
126 changes: 126 additions & 0 deletions conans/client/client_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import os
from conans.util.files import save, load, relative_dirs, path_exists
from conans.model.settings import Settings
from conans.client.conf import ConanClientConfigParser, default_client_conf, default_settings_yml
from conans.model.values import Values
from conans.client.detect import detect_defaults_settings
from conans.model.ref import ConanFileReference
from os.path import isfile
from conans.model.manifest import FileTreeManifest
from conans.paths import CONAN_MANIFEST, SimplePaths

CONAN_CONF = 'conan.conf'
CONAN_SETTINGS = "settings.yml"
LOCALDB = ".conan.db"
REGISTRY = "registry.txt"


class ClientCache(SimplePaths):
""" Class to represent/store/compute all the paths involved in the execution
of conans commands. Accesses to real disk and reads/write things. (OLD client ConanPaths)
"""

def __init__(self, base_folder, store_folder, output):
self.conan_folder = os.path.join(base_folder, ".conan")
self._conan_config = None
self._settings = None
self._output = output
self._store_folder = store_folder or self.conan_config.storage_path or self.conan_folder
super(ClientCache, self).__init__(self._store_folder)

@property
def registry(self):
return os.path.join(self.conan_folder, REGISTRY)

@property
def conan_config(self):
def generate_default_config_file():
default_settings = detect_defaults_settings(self._output)
default_setting_values = Values.from_list(default_settings)
client_conf = default_client_conf + default_setting_values.dumps()
save(self.conan_conf_path, client_conf)

if not self._conan_config:
if not os.path.exists(self.conan_conf_path):
generate_default_config_file()

self._conan_config = ConanClientConfigParser(self.conan_conf_path)

return self._conan_config

@property
def localdb(self):
return os.path.join(self.conan_folder, LOCALDB)

@property
def conan_conf_path(self):
return os.path.join(self.conan_folder, CONAN_CONF)

@property
def settings_path(self):
return os.path.join(self.conan_folder, CONAN_SETTINGS)

@property
def settings(self):
"""Returns {setting: [value, ...]} defining all the possible
settings and their values"""
if not self._settings:
if not os.path.exists(self.settings_path):
save(self.settings_path, default_settings_yml)
settings = Settings.loads(default_settings_yml)
else:
content = load(self.settings_path)
settings = Settings.loads(content)
settings.values = self.conan_config.settings_defaults
self._settings = settings
return self._settings

def export_paths(self, conan_reference):
''' Returns all file paths for a conans (relative to conans directory)'''
return relative_dirs(self.export(conan_reference))

def package_paths(self, package_reference):
''' Returns all file paths for a package (relative to conans directory)'''
return relative_dirs(self.package(package_reference))

def conan_packages(self, conan_reference):
""" Returns a list of package_id from a conans """
assert isinstance(conan_reference, ConanFileReference)
packages_dir = self.packages(conan_reference)
try:
packages = [dirname for dirname in os.listdir(packages_dir)
if not isfile(os.path.join(packages_dir, dirname))]
except: # if there isn't any package folder
packages = []
return packages

def load_digest(self, conan_reference):
'''conan_id = sha(zip file)'''
filename = os.path.join(self.export(conan_reference), CONAN_MANIFEST)
return FileTreeManifest.loads(load(filename))

def conan_manifests(self, conan_reference):
digest_path = self.digestfile_conanfile(conan_reference)
return self._digests(digest_path)

def package_manifests(self, package_reference):
digest_path = self.digestfile_package(package_reference)
return self._digests(digest_path)

def _digests(self, digest_path):
if not path_exists(digest_path, self.store):
return None, None
readed_digest = FileTreeManifest.loads(load(digest_path))
expected_digest = FileTreeManifest.create(os.path.dirname(digest_path))
return readed_digest, expected_digest

def delete_empty_dirs(self, deleted_refs):
for ref in deleted_refs:
ref_path = self.conan(ref)
for _ in range(4):
if os.path.exists(ref_path):
try: # Take advantage that os.rmdir does not delete non-empty dirs
os.rmdir(ref_path)
except OSError:
break # not empty
ref_path = os.path.dirname(ref_path)
86 changes: 51 additions & 35 deletions conans/client/command.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from conans.client.paths import ConanPaths
import sys
import os
from conans.client.output import ConanOutput, Color
import argparse
from conans.errors import ConanException
Expand All @@ -27,6 +24,11 @@
from conans.client.remote_registry import RemoteRegistry
from conans.model.scope import Scopes
import re
from conans.search import DiskSearchManager, DiskSearchAdapter
import sys
import os
from conans.client.client_cache import ClientCache
from conans.util.env_reader import get_env


class Extender(argparse.Action):
Expand Down Expand Up @@ -61,13 +63,13 @@ class Command(object):
collaborators.
It can also show help of the tool
"""
def __init__(self, paths, user_io, runner, remote_manager):
def __init__(self, client_cache, user_io, runner, remote_manager, search_manager):
assert isinstance(user_io, UserIO)
assert isinstance(paths, ConanPaths)
self._conan_paths = paths
assert isinstance(client_cache, ClientCache)
self._client_cache = client_cache
self._user_io = user_io
self._runner = runner
self._manager = ConanManager(paths, user_io, runner, remote_manager)
self._manager = ConanManager(client_cache, user_io, runner, remote_manager, search_manager)

def _parse_args(self, parser):
parser.add_argument("-r", "--remote", help='look for in the remote storage')
Expand Down Expand Up @@ -528,7 +530,7 @@ def user(self, *parameters):
args = parser.parse_args(*parameters) # To enable -h

if args.clean:
localdb = LocalDB(self._conan_paths.localdb)
localdb = LocalDB(self._client_cache.localdb)
localdb.init(clean=True)
self._user_io.out.success("Deleted user data")
return
Expand All @@ -538,23 +540,27 @@ def search(self, *args):
""" show local/remote packages
"""
parser = argparse.ArgumentParser(description=self.search.__doc__, prog="conan search")
parser.add_argument('pattern', nargs='?', help='Pattern name, e.g., openssl/*')
parser.add_argument('pattern', nargs='?', help='Pattern name, e.g. openssl/* or package recipe reference if "-q" is used. e.g. MyPackage/1.2@user/channel')
parser.add_argument('--case-sensitive', default=False,
action='store_true', help='Make a case-sensitive search')
parser.add_argument('-r', '--remote', help='Remote origin')
parser.add_argument('-v', '--verbose', default=False,
action='store_true', help='Show packages')
parser.add_argument('-x', '--extra-verbose', default=False,
action='store_true', help='Show packages options and settings')
parser.add_argument('-p', '--package', help='Package ID pattern. EX: 23*', default=None)
parser.add_argument('-q', '--query', default=None, help='Packages query: "os=Windows AND arch=x86". The "pattern" parameter has to be a package recipe reference: MyPackage/1.2@user/channel')
args = parser.parse_args(*args)

self._manager.search(args.pattern,
reference = None
if args.pattern:
try:
reference = ConanFileReference.loads(args.pattern)
except ConanException:
if args.query is not None:
raise ConanException("-q parameter only allowed with a valid recipe "
"reference as search pattern. e.j conan search "
"MyPackage/1.2@user/channel -q \"os=Windows\"")

self._manager.search(reference or args.pattern,
args.remote,
ignorecase=not args.case_sensitive,
verbose=args.verbose,
extra_verbose=args.extra_verbose,
package_pattern=args.package)
packages_query=args.query)

def upload(self, *args):
""" uploads a conanfile or binary packages from the local store to any remote.
Expand Down Expand Up @@ -615,7 +621,7 @@ def remote(self, *args):
parser_pupd.add_argument('remote', help='name of the remote')
args = parser.parse_args(*args)

registry = RemoteRegistry(self._conan_paths.registry, self._user_io.out)
registry = RemoteRegistry(self._client_cache.registry, self._user_io.out)
if args.subcommand == "list":
for r in registry.remotes:
self._user_io.out.info("%s: %s" % (r.name, r.url))
Expand Down Expand Up @@ -695,39 +701,40 @@ def run(self, *args):
return errors


def migrate_and_get_paths(base_folder, out, manager, storage_folder=None):
def migrate_and_get_client_cache(base_folder, out, manager, storage_folder=None):
# Init paths
paths = ConanPaths(base_folder, storage_folder, out)
client_cache = ClientCache(base_folder, storage_folder, out)

# Migration system
migrator = ClientMigrator(paths, Version(CLIENT_VERSION), out, manager)
migrator = ClientMigrator(client_cache, Version(CLIENT_VERSION), out, manager)
migrator.migrate()

# Init again paths, migration could change config
paths = ConanPaths(base_folder, storage_folder, out)
return paths
client_cache = ClientCache(base_folder, storage_folder, out)
return client_cache


def get_command():

def instance_remote_manager(paths):
def instance_remote_manager(client_cache):
requester = requests.Session()
requester.proxies = paths.conan_config.proxies
requester.proxies = client_cache.conan_config.proxies
# Verify client version against remotes
version_checker_requester = VersionCheckerRequester(requester, Version(CLIENT_VERSION),
Version(MIN_SERVER_COMPATIBLE_VERSION),
out)
# To handle remote connections
rest_api_client = RestApiClient(out, requester=version_checker_requester)
# To store user and token
localdb = LocalDB(paths.localdb)
localdb = LocalDB(client_cache.localdb)
# Wraps RestApiClient to add authentication support (same interface)
auth_manager = ConanApiAuthManager(rest_api_client, user_io, localdb)
# Handle remote connections
remote_manager = RemoteManager(paths, auth_manager, out)
remote_manager = RemoteManager(client_cache, auth_manager, out)
return remote_manager

if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
use_color = get_env("CONAN_COLOR_DISPLAY", 1)
if use_color and hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
import colorama
colorama.init()
color = True
Expand All @@ -740,18 +747,27 @@ def instance_remote_manager(paths):

try:
# To capture exceptions in conan.conf parsing
paths = ConanPaths(user_folder, None, out)
client_cache = ClientCache(user_folder, None, out)
# obtain a temp ConanManager instance to execute the migrations
remote_manager = instance_remote_manager(paths)
manager = ConanManager(paths, user_io, ConanRunner(), remote_manager)
paths = migrate_and_get_paths(user_folder, out, manager)
remote_manager = instance_remote_manager(client_cache)

# Get a DiskSearchManager
search_adapter = DiskSearchAdapter()
search_manager = DiskSearchManager(client_cache, search_adapter)
manager = ConanManager(client_cache, user_io, ConanRunner(), remote_manager, search_manager)

client_cache = migrate_and_get_client_cache(user_folder, out, manager)
except Exception as e:
out.error(str(e))
sys.exit(True)

# Get the new command instance after migrations have been done
manager = instance_remote_manager(paths)
command = Command(paths, user_io, ConanRunner(), manager)
remote_manager = instance_remote_manager(client_cache)

# Get a search manager
search_adapter = DiskSearchAdapter()
search_manager = DiskSearchManager(client_cache, search_adapter)
command = Command(client_cache, user_io, ConanRunner(), remote_manager, search_manager)
return command


Expand Down
2 changes: 1 addition & 1 deletion conans/client/conf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import urllib
from conans.paths import conan_expand_user

MIN_SERVER_COMPATIBLE_VERSION = '0.6.0'
MIN_SERVER_COMPATIBLE_VERSION = '0.12.0'

default_settings_yml = """
os: [Windows, Linux, Macos, Android, iOS]
Expand Down
2 changes: 1 addition & 1 deletion conans/client/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from conans.util.files import save, load, rmdir
from conans.paths import CONAN_MANIFEST, CONANFILE, DIRTY_FILE
from conans.errors import ConanException
from conans.client.file_copier import FileCopier
from conans.model.manifest import FileTreeManifest
from conans.client.output import ScopedOutput
from conans.client.file_copier import FileCopier


def export_conanfile(output, paths, file_patterns, origin_folder, conan_ref, shorten, keep_source):
Expand Down
5 changes: 4 additions & 1 deletion conans/client/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ def execute(self):
file_copier = FileCopier(root_src_folder, self._dst_folder)
copied_files = set()
for pattern, dst_folder, src_folder, conan_name_pattern in self._copies:
real_dst_folder = os.path.normpath(os.path.join(self._dst_folder, dst_folder))
if os.path.isabs(dst_folder):
real_dst_folder = dst_folder
else:
real_dst_folder = os.path.normpath(os.path.join(self._dst_folder, dst_folder))
matching_paths = self._get_paths(conan_name_pattern)
for matching_path in matching_paths:
real_src_folder = os.path.join(matching_path, src_folder)
Expand Down
6 changes: 5 additions & 1 deletion conans/client/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from conans.client.output import ScopedOutput
from conans.model.env_info import EnvInfo
import six
from conans.client.file_copier import report_copied_files


def init_info_objects(deps_graph, paths):
Expand Down Expand Up @@ -317,6 +318,8 @@ def check_max_path_len(src, files):
conan_file.copy = local_installer
conan_file.imports()
copied_files = local_installer.execute()
import_output = ScopedOutput("%s imports()" % output.scope, output)
report_copied_files(copied_files, import_output)

try:
# This is necessary because it is different for user projects
Expand All @@ -338,6 +341,7 @@ def check_max_path_len(src, files):
# Now remove all files that were imported with imports()
for f in copied_files:
try:
os.remove(f)
if(f.startswith(build_folder)):
os.remove(f)
except Exception:
self._out.warn("Unable to remove imported file from build: %s" % f)
Loading

0 comments on commit 54a9817

Please sign in to comment.