Exemple #1
0
def generate_cgo_file(
    installed_lib_paths: List[Path],
    lib_names: List[str],
    installed_include_paths: List[Path],
    go_os: str,
    go_arch: str,
) -> None:
    libs = [str(x) for x in installed_lib_paths]
    libs.extend([f"-l{lib}" for lib in lib_names])
    if go_os in ("linux", "windows"):
        libs.extend(["-static-libstdc++", "-static-libgcc"])
    template_file = Path.cwd() / "cgo_template.go.in"
    # having go_os and go_arch in the filename acts as an implicit build rule
    # e.g. only build cgo_linux_amd64.go on Linux amd64
    dst_file = Path.cwd() / "core" / f"cgo_{go_os}_{go_arch}.go"
    ui.info_1(f"Generating {dst_file}")
    shutil.copy(template_file, dst_file)
    content = dst_file.read_text()
    content = content.replace(
        "{{INCLUDEDIRS}}",
        " ".join([f"-I{dir}" for dir in installed_include_paths]),
    )
    content = content.replace("{{LIBS}}", " ".join(libs))
    with open(dst_file, mode="w") as f:
        f.write(content)
Exemple #2
0
    def _prepare_profile(self) -> None:
        conan_out = self.src_path / "conan" / "out" / self.profile
        package_path = conan_out / "package"
        depsConfig = DepsConfig(self.src_path / "conan" / "out" / self.profile)

        self._copy_includes(package_path, depsConfig)

        native_path = self.src_path / "native" / self.target_triplet
        if native_path.exists():
            shutil.rmtree(native_path)

        native_path.mkdir(parents=True)

        if self._is_windows_target:
            for lib_path in depsConfig.all_lib_paths():
                ui.info_1("copying", lib_path, "to", native_path)
                shutil.copy(lib_path, native_path)
            # handle mingw target
            mingw_path = self.src_path / "native" / "x86_64-pc-windows-gnu"
            # prepare is called twice, so ignore when dirs exists
            shutil.copytree(native_path, mingw_path, dirs_exist_ok=True)
        else:
            self._merge_all_libs(depsConfig, package_path, native_path)
        include_path = package_path / "include" / "ctanker"
        bind_gen(
            header_source=include_path / "ctanker.h",
            output_file=native_path / "ctanker.rs",
            include_path=include_path,
            dynamic_loading=self._is_windows_target,
        )
        if self._is_windows_target:
            shutil.copyfile(native_path / "ctanker.rs",
                            mingw_path / "ctanker.rs")
Exemple #3
0
def build(*, native_from_sources: bool) -> None:
    ui.info_1("build everything")
    if native_from_sources:
        ci.run("./gradlew", "tanker-bindings:buildNativeRelease")
    else:
        ci.run("./gradlew", "tanker-bindings:useDeployedNativeRelease")
    ci.run("./gradlew", "tanker-bindings:assembleRelease")
Exemple #4
0
def generate_token(github_client: github3.GitHub) -> str:
    ui.info_1("Creating new GitHub token")
    username = ui.ask_string("Please enter you GitHub username")
    password = getpass.getpass("Password: "******"repo"]

    # Need a different note for each device, otherwise
    # gh_api.authorize() will fail
    note = "tsrc-" + str(uuid.uuid4())
    note_url = "https://TankerHQ.github.io/tsrc"

    def ask_2fa() -> str:
        return cast(str, ui.ask_string("2FA code: "))

    authorization = github3.authorize(
        username,
        password,
        scopes,
        note=note,
        note_url=note_url,
        two_factor_callback=ask_2fa,
        github=github_client,
    )
    return cast(str, authorization.token)
Exemple #5
0
def run(args: argparse.Namespace) -> None:
    workspace_path = args.workspace_path or Path.cwd()

    cfg_path = workspace_path / ".tsrc" / "config.yml"

    if cfg_path.exists():
        raise tsrc.Error(
            f"Workspace already configured. `{cfg_path}` already exists")

    ui.info_1("Configuring workspace in", ui.bold, workspace_path)

    workspace_config = WorkspaceConfig(
        manifest_url=args.manifest_url,
        manifest_branch=args.manifest_branch,
        clone_all_repos=args.clone_all_repos,
        repo_groups=args.groups or [],
        shallow_clones=args.shallow_clones,
        singular_remote=args.singular_remote,
    )

    workspace_config.save_to_file(cfg_path)

    workspace = Workspace(workspace_path)
    workspace.update_manifest()
    manifest = workspace.get_manifest()
    workspace.repos = repos_from_config(manifest, workspace_config)
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.perform_filesystem_operations()
    ui.info_2("Workspace initialized")
    ui.info_2("Configuration written in", ui.bold, workspace.cfg_path)
Exemple #6
0
def main(args: argparse.Namespace) -> None:
    path_as_str = args.workspace_path or os.getcwd()
    workspace_path = Path(path_as_str)
    cfg_path = workspace_path / ".tsrc" / "config.yml"

    if cfg_path.exists():
        raise tsrc.Error("Workspace already configured with file " + cfg_path)

    ui.info_1("Configuring workspace in", ui.bold, workspace_path)

    workspace_config = WorkspaceConfig(
        manifest_url=args.url,
        manifest_branch=args.branch,
        clone_all_repos=args.clone_all_repos,
        repo_groups=args.groups,
        shallow_clones=args.shallow,
    )

    workspace_config.save_to_file(cfg_path)

    workspace = Workspace(workspace_path)
    workspace.update_manifest()
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.copy_files()
    ui.info_2("Workspace initialized")
    ui.info_2("Configuration written in", ui.bold, workspace.cfg_path)
Exemple #7
0
def run(args: argparse.Namespace) -> None:
    force = args.force
    update_manifest = args.update_manifest
    groups = args.groups
    all_cloned = args.all_cloned
    regex = args.regex
    iregex = args.iregex
    workspace = get_workspace(args)
    num_jobs = get_num_jobs(args)

    if update_manifest:
        ui.info_2("Updating manifest")
        workspace.update_manifest()
    else:
        ui.info_2("Not updating manifest")

    workspace.repos = resolve_repos(workspace,
                                    groups=groups,
                                    all_cloned=all_cloned,
                                    regex=regex,
                                    iregex=iregex)

    workspace.clone_missing(num_jobs=num_jobs)
    workspace.set_remotes(num_jobs=num_jobs)
    workspace.sync(force=force, num_jobs=num_jobs)
    workspace.perform_filesystem_operations()
    ui.info_1("Workspace synchronized")
Exemple #8
0
 def handle_sdk_deps(self, *, tanker_conan_ref: str) -> None:
     ui.info_1("Installing sdk-native for archs: ", self.archs)
     # clean last build files, to avoid losing 2 days when an unexpected binary is used.
     self.conan_out_path.rmtree_p()
     self.install_sdk_native(tanker_conan_ref)
     self.generate_fat_libraries()
     self.copy_headers()
Exemple #9
0
    def handle_sdk_deps(self) -> None:
        ui.info_1("copying sdk-native for profiles: ",
                  [str(p) for p in self.host_profiles])

        for host_profile in self.host_profiles:
            specific_arch_path = self.libraries_path / str(host_profile)
            specific_arch_path.mkdir(parents=True, exist_ok=True)
            libs_path = DepsConfig(
                self.get_build_path(host_profile)).all_lib_paths()
            self.builder.merge_libraries(
                libs=list(libs_path),
                keep_symbols_regex="^_?tanker_.*",
                output_path=specific_arch_path / "libtankerdeps.a",
            )
        self.copy_headers()

        libs = [
            self.libraries_path / str(p) / "libtankerdeps.a"
            for p in self.host_profiles
        ]
        xcframework_path = (self.src_path / "Tanker" / "Frameworks" /
                            "TankerDeps.xcframework")
        self.builder.generate_xcframework(
            xcframework_path=xcframework_path,
            libs=libs,
            include_path=self.private_headers_path,
            output_lib_filename="libtankerdeps.a",
        )
Exemple #10
0
def build_and_test() -> None:
    ui.info_1("Building everything")
    tankerci.run("./gradlew", "assemble")

    ui.info_1("Running tests")
    # In case you're wondering:
    # https://stackoverflow.com/questions/50104666/gradle-difference-between-test-and-check
    tankerci.run("./gradlew", "test")
Exemple #11
0
def deploy(*, git_tag: str) -> None:
    version = tankerci.version_from_git_tag(git_tag)
    tankerci.bump_files(version)
    build_and_test()

    ui.info_1("Deploying Identity SDK to maven.tanker.io")
    tankerci.gcp.GcpProject("tanker-prod").auth()
    tankerci.run("./gradlew", "publish")
Exemple #12
0
def deploy(*, version: str, tanker_ref: str) -> None:
    tankerci.bump_files(version)
    prepare(TankerSource.DEPLOYED, False, tanker_ref)
    build()

    ui.info_1("Deploying SDK to https://storage.googleapis.com/maven.tanker.io")
    tankerci.gcp.GcpProject("tanker-prod").auth()
    tankerci.run("./gradlew", "tanker-bindings:publish")
Exemple #13
0
 def copy_test_sources(self) -> None:
     # trick cocoapods copy the Dummy.m to avoid error during validation
     ui.info_1("Copying dummy test file")
     dummy_test_path = self.src_path / "Tanker/Tests/Dummy.m"
     dest_path = self.dest_path / "Tests"
     dest_path.makedirs_p()
     ui.info_2(dummy_test_path, "->", dest_path)
     dummy_test_path.copy(dest_path)
Exemple #14
0
 def copy_test_sources(self) -> None:
     # trick cocoapods copy the Dummy.m to avoid error during validation
     ui.info_1("Copying dummy test file")
     dummy_test_path = self.src_path / "Tanker/Tests/Dummy.m"
     dest_path = self.dest_path / "Tests"
     dest_path.mkdir(parents=True, exist_ok=True)
     ui.info_2(dummy_test_path, "->", dest_path)
     shutil.copy(dummy_test_path, dest_path)
Exemple #15
0
def init(working_path: Path, *, current_version: str) -> None:
    """ Interactively creates a new tbump.toml """
    ui.info_1("Generating tbump config file")
    tbump_path = working_path / "tbump.toml"
    if tbump_path.exists():
        ui.fatal(tbump_path, "already exists")
    template = textwrap.dedent("""\
        # Uncomment this if your project is hosted on GitHub:
        # github_url = https://github.com/<user or organization>/<project>/

        [version]
        current = "@current_version@"

        # Example of a semver regexp.
        # Make sure this matches current_version before
        # using tbump
        regex = '''
          (?P<major>\\d+)
          \\.
          (?P<minor>\\d+)
          \\.
          (?P<patch>\\d+)
          '''

        [git]
        message_template = "Bump to {new_version}"
        tag_template = "v{new_version}"
     """)

    file_template = textwrap.dedent("""
        # For each file to patch, add a [[file]] config section containing
        # the path of the file, relative to the tbump.toml location.
        [[file]]
        src = "..."
    """)

    hooks_template = textwrap.dedent("""
        # You can specify a list of commands to
        # run after the files have been patched
        # and before the git commit is made

        #  [[before_commit]]
        #  name = "check changelog"
        #  cmd = "grep -q {new_version} Changelog.rst"

        # Or run some commands after the git tag and the branch
        # have been pushed:
        #  [[after_push]]
        #  name = "publish"
        #  cmd = "./publish.sh"
    """)

    to_write = template.replace("@current_version@", current_version)
    to_write += file_template
    to_write += hooks_template
    tbump_path.write_text(to_write)
    ui.info_2(ui.check, "Generated tbump.toml")
Exemple #16
0
def main(args: argparse.Namespace) -> None:
    workspace = tsrc.cli.get_workspace(args)
    manifest_path = args.manifest_path
    ui.info_1("Applying manifest from", args.manifest_path)

    workspace.local_manifest = LocalManifest(manifest_path.parent)
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.copy_files()
Exemple #17
0
def deploy(*, git_tag: str) -> None:
    version = ci.version_from_git_tag(git_tag)
    ci.bump_files(version)
    build(native_from_sources=False)
    test()

    ui.info_1("Deploying SDK to maven.tanker.io")
    ci.gcp.GcpProject("tanker-prod").auth()
    ci.run("./gradlew", "tanker-bindings:publish")
Exemple #18
0
def test() -> None:
    ui.info_1("Running tests")
    config_path = ci.tanker_configs.get_path()
    ci.run(
        "./gradlew",
        "tanker-bindings:testRelease",
        f"-DTANKER_CONFIG_FILEPATH={config_path}",
        "-DTANKER_CONFIG_NAME=dev",
    )
Exemple #19
0
 def generate_archive(self) -> Path:
     version = self.get_version_from_spec()
     ui.info_1("Generating archive, version:", version)
     archive_name = "tanker-ios-sdk-%s.tar.gz" % version
     with tankerci.working_directory(self.dest_path):
         tankerci.run("tar cfvz %s *" % archive_name, shell=True)
         shutil.copy(archive_name, self.src_path)
         res = self.src_path / archive_name
     ui.info_2("Generated", res)
     return res
Exemple #20
0
def apply_manifest(workspace: tsrc.Workspace, manifest_path: Path,
                   **kwargs: Any) -> None:
    """ apply a local manifest file """
    ui.info_1("Applying manifest from", manifest_path)

    manifest = tsrc.manifest.load(manifest_path)
    workspace.repos = repos_from_config(manifest, workspace.config)
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.perform_filesystem_operations()
def ask_or_default(name, label, defaults={}):
    result = ''

    if name not in defaults.keys():
        result = cli_ui.ask_string(label + '?')
    else:
        result = defaults[name]
        cli_ui.info_1(label + ':', result)

    return result
Exemple #22
0
def main(args: argparse.Namespace) -> None:
    workspace_path = args.workspace_path or os.getcwd()
    workspace = tsrc.Workspace(Path(workspace_path))
    ui.info_1("Configuring workspace in", ui.bold, workspace_path)
    manifest_config = tsrc.workspace.ManifestConfig.from_args(args)
    workspace.configure_manifest(manifest_config)
    workspace.load_manifest()
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.copy_files()
    ui.info("Done", ui.check)
Exemple #23
0
def run(args: argparse.Namespace) -> None:
    # Note:
    # we want to support both:
    #  $ tsrc foreach -c 'shell command'
    #  and
    #  $ tsrc foreach -- some-cmd --some-opts
    #
    # Due to argparse limitations, `cmd` will always be a list,
    # but we need a *string* when using 'shell=True'.
    #
    # So transform use the value from `cmd` and `shell` so that:
    # * action.command is suitable as argument to pass to subprocess.run()
    # * action.description is suitable for display purposes
    command: Command = []
    if args.shell:
        if len(args.cmd) != 1:
            die("foreach -c must be followed by exactly one argument")
        command = args.cmd[0]
        description = args.cmd[0]
    else:
        if not args.cmd:
            die("needs a command to run")
        command = args.cmd
        description = " ".join(args.cmd)
    shell = args.shell
    command = command
    description = description
    num_jobs = get_num_jobs(args)

    workspace = get_workspace_with_repos(args)
    cmd_runner = CmdRunner(workspace.root_path,
                           command,
                           description,
                           shell=shell)
    repos = workspace.repos
    ui.info_1(f"Running `{description}` on {len(repos)} repos")
    collection = process_items(repos, cmd_runner, num_jobs=num_jobs)
    errors = collection.errors
    if errors:
        ui.error(f"Command failed for {len(errors)} repo(s)")
        if cmd_runner.parallel:
            # Print output of failed commands that were hidden
            for (item, error) in errors.items():
                ui.info(item)
                ui.info("-" * len(item))
                ui.info(error)
        else:
            # Just print the repos
            for item in errors:
                ui.info(ui.green, "*", ui.reset, item)
        raise ForeachError()
    else:
        ui.info("OK", ui.check)
Exemple #24
0
    def copy_sources(self) -> None:
        ui.info_1("Copying sources")
        sources_path = self.src_path / "Tanker/Sources"

        ui.info_2(sources_path, "->", self.dest_path)
        sources_path.copytree(self.dest_path / "Sources")

        export_list_src = self.src_path / "Tanker/export_symbols.list"
        export_list_dest = self.dest_path / "export_symbols.list"

        ui.info_2(export_list_src, "->", export_list_dest)
        export_list_src.copy(export_list_dest)
Exemple #25
0
def _copy_folder_content(src_path: Path, dest_path: Path) -> None:
    ui.info_1("Moving content of", src_path, "to", dest_path)
    for src_dir in src_path.dirs():
        dest_dir = dest_path / src_dir.basename()
        dest_dir.rmtree_p()
        ui.info_2(src_dir, "->", dest_dir)
        src_dir.copytree(dest_dir)
    for src_file in src_path.files():
        dest_file = dest_path / src_file.basename()
        dest_file.remove_p()
        ui.info_2(src_file, "->", dest_file)
        src_file.copy2(dest_file)
Exemple #26
0
    def generate_fat_libraries(self) -> None:
        ui.info_1("Generating fat libraries")
        self.libraries_path.rmtree_p()
        self.libraries_path.makedirs_p()

        for lib_name, libs in self.get_all_dependency_libs().items():
            output = self.libraries_path / lib_name
            ci.run("lipo",
                   "-create",
                   "-output",
                   output,
                   *libs,
                   cwd=self.conan_out_path)
Exemple #27
0
def prepare(
    profile: str,
    tanker_source: TankerSource,
    update: bool,
    tanker_ref: Optional[str] = None,
) -> None:
    profile_prefix = profile.split("-")[0]
    go_os, go_arch = PROFILE_OS_ARCHS[profile_prefix]
    conan_out = Path.cwd() / "conan"
    if tanker_source == TankerSource.DEPLOYED and not tanker_ref:
        tanker_ref = "tanker/latest-stable@"

    tankerci.conan.install_tanker_source(
        tanker_source,
        output_path=conan_out,
        profiles=[profile],
        update=update,
        tanker_deployed_ref=tanker_ref,
    )
    conan_path = [x for x in conan_out.iterdir() if x.is_dir()][0]
    deps_info = DepsConfig(conan_path)
    go_install = Path("ctanker") / f"{go_os}-{go_arch}"
    install_path = Path.cwd() / "core" / go_install

    if tanker_source == TankerSource.DEPLOYED:
        copy_deps(deps_info, install_path)
        installed_include_path = install_path / "include"
        ui.info_1(f"cleaning {installed_include_path}")
        tanker_headers = installed_include_path / "Tanker"
        helpers_headers = installed_include_path / "Helpers"
        if tanker_headers.exists():
            shutil.rmtree(tanker_headers)
        if helpers_headers.exists():
            shutil.rmtree(helpers_headers)
        generate_cgo_file(
            [Path("-L${SRCDIR}") / go_install / "lib"],
            list(deps_info.all_libs()),
            [go_install / "include"],
            go_os,
            go_arch,
        )
    else:
        generate_cgo_file(
            list(deps_info.all_lib_paths()),
            list(deps_info.all_system_libs()),
            deps_info["tanker"].include_dirs,
            go_os,
            go_arch,
        )
Exemple #28
0
def _copy_folder_content(src_path: Path, dest_path: Path) -> None:
    ui.info_1("Moving content of", src_path, "to", dest_path)
    src_dirs = [p for p in src_path.iterdir() if p.is_dir()]
    for src_dir in src_dirs:
        dest_dir = dest_path / src_dir.name
        if dest_dir.exists():
            shutil.rmtree(dest_dir)
        ui.info_2(src_dir, "->", dest_dir)
        shutil.copytree(src_dir, dest_dir)
    src_files = [p for p in src_path.iterdir() if p.is_file()]
    for src_file in src_files:
        dest_file = dest_path / src_file.name
        if dest_file.exists():
            dest_file.unlink()
        ui.info_2(src_file, "->", dest_file)
        shutil.copy2(src_file, dest_file)
Exemple #29
0
def main(args: argparse.Namespace) -> None:
    workspace_path = args.workspace_path or os.getcwd()
    workspace = tsrc.Workspace(Path(workspace_path))
    ui.info_1("Configuring workspace in", ui.bold, workspace_path)
    as_dict = vars(args)
    relevant_keys = [x.name for x in attr.fields(ManifestConfig)]
    for key in list(as_dict.keys()):
        if key not in relevant_keys:
            del as_dict[key]
    manifest_config = ManifestConfig.from_dict(as_dict)
    workspace.configure_manifest(manifest_config)
    workspace.load_manifest()
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.copy_files()
    ui.info("Done", ui.check)
Exemple #30
0
def main():
    ui.info_1("Starting CI")
    all_checks = init_checks()
    check_list = sys.argv[1:]
    checks = all_checks
    if check_list:
        checks = [c for c in checks if c.name in check_list]
    for check in checks:
        check.run()
    failed_checks = [check for check in checks if not check.ok]
    if not failed_checks:
        ui.info(ui.green, "CI passed")
        return
    for check in failed_checks:
        ui.error(check.name, "failed")
    sys.exit(1)