text:
package com.mcleodmoores.examples.simulated.component;

import com.opengamma.component.OpenGammaComponentServer;
import com.opengamma.util.ShutdownUtils;

/**
 *
 */
public class ExampleSimulatedComponentServer extends OpenGammaComponentServer {

  public static void main(final String[] clArgs) {
    String[] args;
    if (clArgs.length == 0) {
      args = new String[] { "-v", "classpath:/fullstack/fullstack-mmexamples-dev.properties" };
    } else {
      args = clArgs;
    }
    OpenGammaComponentServer.setStartingMessage("======== STARTING STARLING ========");
    OpenGammaComponentServer.setStartupCompleteMessage("======== STARLING STARTED in ");
    OpenGammaComponentServer.setStartupFailedMessage("======== STARLING STARTUP FAILED ========");
    if (!new ExampleSimulatedComponentServer().run(args)) {
      ShutdownUtils.exit(-1);
    }
  }
}


text:
import { Component } from "../../widgets/component";
import { ICellRenderer, ICellRendererParams } from "./iCellRenderer";
import { RefSelector } from "../../widgets/componentAnnotations";
import { createIconNoSpan } from "../../utils/icon";

export interface ILoadingCellRendererParams extends ICellRendererParams {}
export interface ILoadingCellRenderer extends ICellRenderer {}

export class LoadingCellRenderer extends Component implements ILoadingCellRenderer {

    private static TEMPLATE =
        `

`;

    @RefSelector('eLoadingIcon') private eLoadingIcon: HTMLElement;
    @RefSelector('eLoadingText') private eLoadingText: HTMLElement;

    constructor() {
        super(LoadingCellRenderer.TEMPLATE);
    }

    public init(params: ILoadingCellRendererParams): void {
        params.node.failedLoad ? this.setupFailed() : this.setupLoading();
    }

    private setupFailed(): void {
        this.eLoadingText.innerText = 'ERR';
    }

    private setupLoading(): void {
        const eLoadingIcon = createIconNoSpan('groupLoading', this.gridOptionsWrapper, null);
        this.eLoadingIcon.appendChild(eLoadingIcon);

        const localeTextFunc = this.gridOptionsWrapper.getLocaleTextFunc();
        this.eLoadingText.innerText = localeTextFunc('loadingOoo', 'Loading');
    }

    public refresh(params: any): boolean {
        return false;
    }
}

redpajama_set_name: RedPajamaGithub


text:
package types

// Process type.
//
// https://github.com/elastic/elasticsearch-specification/blob/4ca0cc05d3ae3fa06c2cd7be91905b656a474334/specification/nodes/_types/Stats.ts#L375-L381
type Process struct {
	Cpu                 *Cpu         `json:"cpu,omitempty"`
	MaxFileDescriptors  *int         `json:"max_file_descriptors,omitempty"`
	Mem                 *MemoryStats `json:"mem,omitempty"`
	OpenFileDescriptors *int         `json:"open_file_descriptors,omitempty"`
	Timestamp           *int64       `json:"timestamp,omitempty"`
}

// NewProcess returns a Process.
func NewProcess() *Process {
	r := &Process{}

	return r
}


text:
/* @flow */

import React, { Component } from 'react';

import { createDeepLinkingPageEvent, sendAnalytics } from '../../analytics';

declare var interfaceConfig: Object;

/**
 * React component representing no mobile app page.
 *
 * @class NoMobileApp
 */
export default class NoMobileApp extends Component<*> {
    /**
     * Implements the Component's componentDidMount method.
     *
     * @inheritdoc
     */
    componentDidMount() {
        sendAnalytics(
            createDeepLinkingPageEvent(
                'displayed', 'noMobileApp', { isMobileBrowser: true }));
    }

    /**
     * Renders the component.
     *
     * @returns {ReactElement}
     */
    render() {
        const ns = 'no-mobile-app';

        return (

                <h2 className = { `${ns}__title` }>
                    Video chat isn't available on mobile.

                <p className = { `${ns}__description` }>
                    Please use { interfaceConfig.NATIVE_APP_NAME } on desktop to
                    join calls.

        );
    }
}


text:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/white" android:state_checked="true" />
    <item android:color="@color/red_time_line" android:state_checked="false" />
</selector>


text:
void ThrowError(const char* message);
void ThrowErrorWithValue(const char* message, short value);

#endif


text:
"""
mysql_grants_generator is a program to automate the generation of mysql grants
 copyright:  2015, (c) sproutsocial.com
 author:   Nicholas Flink <nicholas@sproutsocial.com>
"""

import argparse
import datetime
import logging
import os
import pprint
import email_tool
import random
import string
import sys
import auto_grant_config
import ldap_query_tool
import mysql_backup_tool
import mysql_query_tool
import util
logger = logging.getLogger(__name__)

PASSWORD_KEY = 'password'
CLUSTERS_KEY = 'clusters'
TEMPLATE_KEY = 'template'
TEMPLATE_ACCESS = 'access'
TEMPLATE_INVITE = 'invite'
RET_MUTEX_ARGS = 10

_mysqlBackupTool = None

class GrantException(Exception):
    """
    Generic GranException
    """
    def __init__(self, message):
        super(GrantException, self).__init__(message)

def _getMysqlBackupTool(echoOnly, logPasswords):
    global _mysqlBackupTool
    if _mysqlBackupTool is None:
        _mysqlBackupTool = mysql_backup_tool.MysqlBackupTool(echoOnly, logPasswords)
    _mysqlBackupTool.setEchoOnly(echoOnly)
    _mysqlBackupTool.setLogPasswords(logPasswords)
    return _mysqlBackupTool

def makeGroupDict(autoGrantConfig, ldapGroupDict):
    """
    this is the ldap group processing
    :param autoGrantConfig: an instance of AutoGrantConfig
    :param ldapGroupDict: a dict with the form:
    {'cn=int_test_group,ou=groups,dc=nodomain': {'cn': ['int_test_group'],
                                                 'gidNumber': ['20000'],
                                                 'memberUid': ['int_test_user'],
                                                 'objectClass': ['top',
                                                                 'posixGroup']},
     'ou=groups,dc=nodomain': {'objectClass': ['organizationalUnit'],
                           'ou': ['groups']}}
    :returns: a dict of the form: {'int_test_group': ['int_test_user']}
    """
    groupDict = {}
    ldapMinGid = autoGrantConfig.getLdapMinGid()
    # add groups from ldap
    for key in ldapGroupDict.keys():
        if 'gidNumber' in ldapGroupDict[key]:
            for gid in ldapGroupDict[key]['gidNumber']:
                if ldapMinGid <= int(gid):
                    cnList = ldapGroupDict[key]['cn']
                    for cn in cnList:
                        if cn not in groupDict and 'memberUid' in ldapGroupDict[key]:
                            # Iterate over these and find any longer than 16 characters and truncate them.
                            # MySQL <= 5.6 has a maximum username length of 16.
                            memberUid = ldapGroupDict[key]['memberUid']
                            for i in range(0, len(memberUid)):
                                member = memberUid[i]
                                if len(member) > 16:
                                    logger.warning("LDAP username %s is longer than 16 characters, truncating to %s", member, member[:16])
                                    memberUid[i] = member[:16]
                            groupDict[cn] = ldapGroupDict[key]['memberUid']
    # add custom mysql groups from config
    customMysqlGroups = autoGrantConfig.getCustomMysqlGroups()
    if customMysqlGroups is not None:
        for group in customMysqlGroups.keys():
            if group not in groupDict:
                groupDict[group] = customMysqlGroups[group]
            else:
                for user in customMysqlGroups[group]:
                    if user not in groupDict[group]:
                        groupDict[group].append(user)
    logger.debug(pprint.pformat(groupDict))
    return groupDict

def makeUserDict(autoGrantConfig, groupDict, userList=None):
    """
    this breaks out the groups by user
    :param autoGrantConfig: an instance of AutoGrantConfig
    :param groupDict: a dict with the form: {'int_test_group': ['int_test_user']}
    :returns: a dict with the form: {'int_test_user@%': set(['int_test_group'])}
    """
    userDict = {}
    reverseDict = {}
    # first pass to just reverse the groupDict
    for group in groupDict.keys():
        for user in groupDict[group]:
            if userList is None or user in userList:
                if user not in reverseDict:
                    reverseDict[user] = set()
                reverseDict[user] |= set([group])
    # second pass to expand users with their @'hosts'
    for user in reverseDict.keys():
        for group in reverseDict[user]:
            hosts = autoGrantConfig.getHostsForGroup(group)
            for host in hosts:
                userKey = user + "@" + host
                if userKey not in userDict:
                    if not autoGrantConfig.getMysqlUserFiltered(userKey):
                        userDict[userKey] = reverseDict[user]
                    else:
                        logger.debug("filtering out user:"+userKey)
    return userDict

def makeGrantDict(autoGrantConfig, userDict, clusterList=None):
    """
    this breaks out the grants by user
    :param autoGrantConfig: an instance of AutoGrantConfig
    :param userDict: a dict with the form: {'int_test_user@%': set(['int_test_group'])}
    :returns: a dict with the form:
        {'192.168.33.10': {'int_test_user@%':
            [{'db_table': '*.*',
              'privileges': ['SELECT', 'FOOEY']},
             {'db_table': 'test_db.test_table',
              'privileges': ['select',
                             'INSERT',
                             'update',
                             'delete']}]}}
    """
    grantDict = {}
    dbClusters = autoGrantConfig.getDbClusters()
    # add the user dicts and get grants per cluster
    for cluster in dbClusters:
        if clusterList is not None and cluster not in clusterList:
            continue
        for user in userDict.keys():
            for group in userDict[user]:
                grantList = autoGrantConfig.getGrantList(user, cluster, group)
                for grant in grantList:
                    if cluster not in grantDict:
                        grantDict[cluster] = {}
                    if user not in grantDict[cluster]:
                        grantDict[cluster][user] = []
                    for userGrant in grantDict[cluster][user]:
                        if userGrant['db_table'] == grant['db_table']:
                            grantDict[cluster][user].remove(userGrant)
                            grant['privileges'] = list(set(userGrant['privileges'] + grant['privileges']))
                            break
                    grantDict[cluster][user].append(grant)
    return grantDict

def grantAccess(autoGrantConfig, grantDict, echoOnly, logPasswords, destructive, passwordReset):
    """ This is the function that grants revokes and drops users
        Before adding any additional logica we should consider splitting
        this function to avoid it getting too unweildy
        NOTE: if destructive is False Revokes and Drop Users will be omitted
    """
    newUserDict = {}
    mysqlBackupTool = _getMysqlBackupTool(echoOnly, logPasswords)
    backupName = mysqlBackupTool.getCurrentTimeBackup()
    grantUser = autoGrantConfig.getMysqlGrantsUsername()
    grantPass = autoGrantConfig.getMysqlGrantsPassword()
    # determine access levels from echoOnly and destructive
    echoAccessLevel = mysql_query_tool.QAL_READ_WRITE
    if destructive or passwordReset:
        echoAccessLevel = mysql_query_tool.QAL_READ_WRITE_DELETE
    queryAccessLevel = echoAccessLevel
    if echoOnly:
        queryAccessLevel = mysql_query_tool.QAL_READ
    defaultCluster = grantDict.keys()[0]
    for cluster in grantDict.keys():
        mysqlBackupTool.performMySQLDumpList(cluster, grantUser, grantPass, backupName, [("mysql", "user")])
        logger.debug("backup saved")
        mysqlConn = mysql_query_tool.MysqlQueryTool(cluster, grantUser,
                                                    grantPass, echoAccessLevel,
                                                    queryAccessLevel, logPasswords)
        logger.debug("connection created")
        for userAtHost in grantDict[cluster].keys():
            logger.debug("working on %s", userAtHost)
            userPart, hostPart = (x.strip("'") for x in userAtHost.split('@'))
            mysqlConn.beginTransaction()
            passwordHash = mysqlConn.getPasswordHash(userPart, hostPart)
            userExists = (passwordHash is not None)
            if passwordReset and userExists:
                mysqlConn.dropUser(userAtHost)
                userExists = False
                passwordHash = None
            if userExists:
                logger.debug("CACHING PASSWORD HASH %s FOR %s ACCOUNT ON %s" % (passwordHash, userAtHost, cluster))
                updateMysqlUser(newUserDict, userAtHost, mysqlConn, passwordHash, None)
            else:
                logger.debug("NEED TO CREATE USER: %s", userAtHost)
                updateMysqlUser(newUserDict, userAtHost, mysqlConn, generateRandomPassword(), cluster)
            grantDeltaDict = {}
            try:
                for grant in grantDict[cluster][userAtHost]:
                    dbTable = grant['db_table']
                    privileges = grant['privileges']
                    grantDeltaDict = mysqlConn.getGrantDeltaDict(userAtHost, dbTable, privileges)
                    if 0 < len(grantDeltaDict['grants']):
                        mysqlConn.queryGrant(userAtHost,
                                             grantDeltaDict['grants'],
                                             dbTable)
                    if 0 < len(grantDeltaDict['revokes']):
                        mysqlConn.queryRevoke(userAtHost,
                                              grantDeltaDict['revokes'],
                                              dbTable)
                        mysqlConn.queryFlushPrivileges()
                mysqlConn.commitTransaction()
            except Exception as e:
                mysqlConn.rollbackTransaction()
                message = e.message + ": An exception occured when trying to grant:[%s] and revoke:[%s] to %s on %s" % (",".join(grantDeltaDict['grants']), ",".join(grantDeltaDict['revokes']), userAtHost, cluster)
                raise GrantException(message)
        if destructive and not passwordReset:
            # remove non defined users
            allMysqlUsers = mysqlConn.findAllUsers()
            usersToDrop = findUsersToDrop(autoGrantConfig, allMysqlUsers,
                                          grantDict[cluster].keys())
            for userToDropWithHost in usersToDrop:
                mysqlConn.dropUser(userToDropWithHost)
        mysqlConn.closeConnection()
    if echoOnly is False:
        sendEmailNotifications(autoGrantConfig, newUserDict, defaultCluster)

def findUsersToDrop(autoGrantConfig, allMysqlUsers, usersWithGrants):
    usersToDrop = []
    for mysqlUser in allMysqlUsers:
        if mysqlUser in usersWithGrants:
            continue
        if not autoGrantConfig.getMysqlUserFiltered(mysqlUser):
            usersToDrop.append(mysqlUser)
    return usersToDrop

def updateMysqlUser(newUserDict, newUserWithHost, mysqlConn, password, cluster=None):
    if newUserWithHost not in newUserDict:
        newUserDict[newUserWithHost] = {CLUSTERS_KEY: set([]),
                                        PASSWORD_KEY: password,
                                        TEMPLATE_KEY: TEMPLATE_INVITE}
        if cluster is None:
            newUserDict[newUserWithHost][TEMPLATE_KEY] = TEMPLATE_ACCESS
        else:
            logger.info("New password invite for %s with password %s",
                        newUserWithHost, password)
    if cluster is not None:
        newUserDict[newUserWithHost][CLUSTERS_KEY] |= set([cluster])
        useHash = newUserDict[newUserWithHost][TEMPLATE_KEY] == TEMPLATE_ACCESS
        newPassword = newUserDict[newUserWithHost][PASSWORD_KEY]
        mysqlConn.createUser(newUserWithHost, newPassword, useHash)

def sendEmailNotifications(autoGrantConfig, newUserDict, defaultCluster):
    email = autoGrantConfig.getEmail()
    emailPass = autoGrantConfig.getEmailPass()
    awsKey = autoGrantConfig.getAWSKey()
    awsSecret = autoGrantConfig.getAWSSecret()
    hastebinUrl = autoGrantConfig.getHasteBinUrl()
    emailTool = email_tool.EmailTool(email, emailPass, awsKey, awsSecret, hastebinUrl)
    ldapEmailMap = autoGrantConfig.getUserToEmailMap()
    for userAtHost in newUserDict.keys():
        clusters = newUserDict[userAtHost][CLUSTERS_KEY]
        if 0 < len(clusters):
            newPassword = newUserDict[userAtHost][PASSWORD_KEY]
            template = newUserDict[userAtHost][TEMPLATE_KEY]
            mysqlUser = userAtHost.split('@')[0].strip("'")
            # If None this will generate the email from [mysqlUser]@[domain of gmail_auth.username in yaml]
            toList = None
            if mysqlUser in ldapEmailMap:
                emailOverride = ldapEmailMap[mysqlUser]
                toList = [emailOverride]
            if template == TEMPLATE_INVITE:
                emailTool.sendChangePasswordInvite(clusters, userAtHost, newPassword, toList)
            else:
                emailTool.sendAccessNotification(clusters, userAtHost, newPassword, defaultCluster, toList)

def generateRandomPassword():
    length = 32
    chars = string.ascii_letters + string.digits
    random.seed = (os.urandom(1024))
    randomPassword = ''.join(random.choice(chars) for i in range(length))
    logger.debug("generateRandomPassword="+randomPassword)
    return randomPassword

def start(autoGrantConfig, echoOnly, logPasswords, destructive, passwordReset, revert, userList, groupList,
          clusterList):
    restoreName = ''
    restorePath = ''
    mysqlBackupTool = _getMysqlBackupTool(echoOnly, logPasswords)

    pruneBeforeDate = mysqlBackupTool.getPruneBeforeFromTimeDelta(
        datetime.timedelta(days=30))
    mysqlBackupTool.pruneBefore(pruneBeforeDate)
    if revert is not False:
        if revert is None:
            # default we use the last backup
            restoreName = mysqlBackupTool.getLastBackup()
        else:
            # default we use the last backup
            restoreName = revert
        backupDir = mysql_backup_tool.DEFAULT_BACKUP_DIR
        if restoreName is not None and 0 < len(restoreName):
            restorePath = os.path.join(backupDir, restoreName)
        if os.path.isdir(restorePath):
            revertUser = autoGrantConfig.getMysqlRevertUsername()
            revertPass = autoGrantConfig.getMysqlRevertPassword()
            mysqlBackupTool = _getMysqlBackupTool(echoOnly, logPasswords)
            for cluster in autoGrantConfig.getDbClusters():
                logger.info("reverting %s", cluster)
                echoAccessLevel = mysql_query_tool.QAL_ALL
                queryAccessLevel = mysql_query_tool.QAL_ALL
                if echoOnly:
                    queryAccessLevel = mysql_query_tool.QAL_NONE
                mysqlConn = mysql_query_tool.MysqlQueryTool(cluster, revertUser,
                                                            revertPass,
                                                            echoAccessLevel,
                                                            queryAccessLevel,
                                                            logPasswords)
                mysqlBackupTool.restoreFromMySQLDumpList(cluster, revertUser,
                                                         revertPass, restoreName,
                                                         [("mysql", "user")])
                mysqlConn.queryFlushPrivileges()
        else:
            logger.error("No backup was found under %s", backupDir)
    else:
        ldapUrl = autoGrantConfig.getLdapURL()
        ldapUsernameBase = autoGrantConfig.getLdapUsernameBase()
        ldapPassword = autoGrantConfig.getLdapPassword()
        ldapGroupDict = {}
        if ldapUrl is None or ldapUsernameBase is None or ldapPassword is None:
            logger.warning("missing one of ldapUrl:%s ldapUsernameBase:%s or ldapPassword:%s [%s]",
                           str(ldapUrl), str(ldapUsernameBase), str(ldapPassword),
                           "this will disable ldap integration")
        else:
            ldapQueryTool = ldap_query_tool.LdapQueryTool(ldapUrl,
                                                          ldapUsernameBase,
                                                          ldapPassword)
            ldapGroupDesc = autoGrantConfig.getLdapGroupDesc()
            ldapGroupDict = ldapQueryTool.queryLDAP(ldapGroupDesc)
        groupDict = makeGroupDict(autoGrantConfig, ldapGroupDict)
        if userList is not None:
            userList = userList.split(",")
        if groupList is not None:
            for group in groupList.split(","):
                if userList is None:
                    userList = []
                userList += groupDict[group]
        logger.debug("groupDict:\n"+pprint.pformat(groupDict))
        userDict = makeUserDict(autoGrantConfig, groupDict, userList)
        logger.debug("userDict:\n"+pprint.pformat(userDict))
        grantDict = makeGrantDict(autoGrantConfig, userDict, clusterList)
        logger.debug("grantDict:\n"+pprint.pformat(grantDict))
        grantAccess(autoGrantConfig, grantDict, echoOnly, logPasswords, destructive, passwordReset)

def init_config(nonInteractive):
    configFile = os.path.join(os.getcwd(), 'auto_grant.yaml')
    if os.path.exists(configFile):
        raise Exception("could not generate auto_grant.yaml file already exists")
    else:
        if nonInteractive:
            mysqlUser = "<%= ENV['AG_MYSQL_USER'] %>"
            mysqlPass = "<%= ENV['AG_MYSQL_PASS'] %>"
            gmailUser = "<%= ENV['AG_GMAIL_USER'] %>"
            gmailPass = "<%= ENV['AG_GMAIL_PASS'] %>"
        else:
            mysqlUser = util.askQuestion("Please enter your mysql user", "grant_user")
            mysqlPass = util.askPassword("Please enter your mysql password", "grant_pass")
            gmailUser = util.askQuestion("Please enter your gmail user")
            gmailPass = util.askPassword("Please enter your gmail password")
        templateArgDict = {'mysqlUser': mysqlUser,
                           'mysqlPass': mysqlPass,
                           'gmailUser': gmailUser,
                           'gmailPass': gmailPass}
        payload = util.renderTemplate("auto_grant.yaml.tmpl",
                                      templateArgDict)
        with open(configFile, 'w') as f:
            f.write(payload)

def main(args=None):
    """Arg parsing and logger setup"""
    retCode = 0
    logLevels = {"DEBUG": logging.DEBUG,
                 "INFO": logging.INFO,
                 "WARN": logging.WARNING,
                 "ERROR": logging.ERROR,
                 "CRITICAL": logging.CRITICAL}
    parser = argparse.ArgumentParser(
        description='A tool to apply grants using ldap groups')
    reqGrp = parser.add_argument_group("required arguments")
    usrGrp = parser.add_argument_group("user arguments")
    dstGrp = parser.add_argument_group("destructive arguments")
    parser.add_argument('-l', '--log-level', type=str, default="INFO",
                        choices=["DEBUG", "INFO", "WARN", "ERROR", "CRITICAL"],
                        help="the log level")
    parser.add_argument('-e', '--echo-only', action='store_true',
                        help="just print out the queries to run")
    parser.add_argument('--non-interactive', action='store_true', default=False,
                        help="just run without any prompting")
    parser.add_argument('-C', '--cluster-list', type=str,
                        help="a comma delimited list of clusters to filter by")
    usrGrp.add_argument('-U', '--user-list', type=str,
                        help="a comma delimited list of users to filter by")
    usrGrp.add_argument('-G', '--group-list', type=str,
                        help="a comma delimited list of groups to filter by")
    dstGrp.add_argument('-r', '--revert', nargs='?', type=str,
                        required=False, default=False,
                        help="restore using the latest backup")
    dstGrp.add_argument('--destructive', action='store_true',
                        required=False, default=False,
                        help="drop users and revoke privileges")
    parser.add_argument('--password-reset', action='store_true',
                        required=False, default=False,
                        help="drop and re-add the user to reset password")
    parser.add_argument('--log-passwords', action='store_true',
                        required=False, default=False,
                        help="useful if you want to pipe the -l CRITICAL output to mysql tool")
    reqGrp.add_argument('-y', '--yaml-conf', type=str, required=False,
                        default=os.path.join(os.getcwd(), 'auto_grant.yaml'),
                        help="the yaml configuration path")
    reqGrp.add_argument('-i', '--init', action='store_true',
                        required=False, default=False,
                        help="create an auto_grant.yaml conf in the current working dir")
    parsedArgs = parser.parse_args(args)
    if parsedArgs.log_level.upper() in logLevels.keys():
        logging.basicConfig(level=logLevels[parsedArgs.log_level.upper()])
    else:
        logging.basicConfig(level=logging.INFO)
        logger.warn("Unknown logLevel=%s retaining level at INFO",
                    parsedArgs.log_level)
    logger.debug(pprint.pformat(parsedArgs))
    if ((parsedArgs.destructive is True or parsedArgs.revert is not False) and
            (parsedArgs.user_list is not None or parsedArgs.group_list is not None)):
        print ("Can not use user arguments in combination with " +
               "destructive arguments")
        retCode = RET_MUTEX_ARGS
    else:
        if parsedArgs.init:
            init_config(parsedArgs.non_interactive)
        else:
            autoGrantConfig = auto_grant_config.AutoGrantConfig(parsedArgs.yaml_conf)
            start(autoGrantConfig, True, parsedArgs.log_passwords, parsedArgs.destructive, parsedArgs.password_reset, parsedArgs.revert,
                  parsedArgs.user_list, parsedArgs.group_list, parsedArgs.cluster_list)
            if(parsedArgs.echo_only is False):
                userInput = "No"
                if parsedArgs.non_interactive is True:
                    logger.info("The above commands will be run %s...",
                                "non-interactively")
                    userInput = "Yes"
                else:
                    userInput = util.askQuestion("Are you sure you would like to run the above commands:\n" +
                                                 "Type %s to continue %s to skip" %
                                                 ("[Yes]", "[Enter]"))
                if userInput == "Yes":
                    start(autoGrantConfig, parsedArgs.echo_only, parsedArgs.log_passwords, parsedArgs.destructive, parsedArgs.password_reset,
                          parsedArgs.revert, parsedArgs.user_list, parsedArgs.group_list,
                          parsedArgs.cluster_list)
                else:
                    logger.info("skipping...")
    logger.info("done.")
    return retCode

if __name__ == "__main__":
    """Entry point if being run as a script"""
    sys.exit(main(sys.argv[1:]))


text:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText
        android:id="@+id/IPText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:ems="10"
        android:hint="主机地址" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/IPText"
        android:onClick="startButton"
        android:text="Button" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

    <TextView
        android:id="@+id/JSONView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:text="JSON" />

    <TextView
        android:id="@+id/MSGView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/textView1"
        android:text="MSG" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/button1"
        android:layout_marginTop="21dp"
        android:text="Button" />

</RelativeLayout>


text:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;

namespace EduHub.Data.Entities
{
    /// <summary>
    /// Houses
    /// </summary>
    [GeneratedCode("EduHub Data", "0.9")]
    public sealed partial class KGH : EduHubEntity
    {

        #region Navigation Property Cache

        private SCI Cache_CAMPUS_SCI;

        #endregion

        #region Foreign Navigation Properties

        private IReadOnlyList<SF> Cache_KGHKEY_SF_HOUSE;
        private IReadOnlyList<SG> Cache_KGHKEY_SG_HOUSE;
        private IReadOnlyList<ST> Cache_KGHKEY_ST_HOUSE;

        #endregion

        /// <inheritdoc />
        public override DateTime? EntityLastModified
        {
            get
            {
                return LW_DATE;
            }
        }

        #region Field Properties

        /// <summary>
        /// (Was HOUSE) House code
        /// [Uppercase Alphanumeric (10)]
        /// </summary>
        public string KGHKEY { get; internal set; }

        /// <summary>
        /// House description
        /// [Alphanumeric (30)]
        /// </summary>
        public string DESCRIPTION { get; internal set; }

        /// <summary>
        /// Campus
        /// </summary>
        public int? CAMPUS { get; internal set; }

        /// <summary>
        /// Active house? (Y/N)
        /// [Uppercase Alphanumeric (1)]
        /// </summary>
        public string ACTIVE { get; internal set; }

        /// <summary>
        /// Number of current students in the house
        /// </summary>
        public short? HOUSE_SIZE { get; internal set; }

        /// <summary>
        /// Number of current males in the house
        /// </summary>
        public short? MALES { get; internal set; }

        /// <summary>
        /// Number of current females in the house
        /// </summary>
        public short? FEMALES { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F01 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F02 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F03 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F04 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F05 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F06 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F07 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F08 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F09 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F10 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F11 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F12 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F13 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F14 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F15 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F16 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F17 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F18 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F19 { get; internal set; }

        /// <summary>
        /// Number of females aged x as at 31st Dec
        /// </summary>
        public short? AGE_F20 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M01 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M02 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M03 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M04 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M05 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M06 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M07 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M08 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M09 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M10 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M11 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M12 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M13 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M14 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M15 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M16 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M17 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M18 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M19 { get; internal set; }

        /// <summary>
        /// Number of males aged x as at 31 dec
        /// </summary>
        public short? AGE_M20 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students in house
        /// </summary>
        public short? SELF_DESCRIBED { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S01 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S02 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S03 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S04 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S05 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S06 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S07 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S08 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S09 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S10 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S11 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S12 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S13 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S14 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S15 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S16 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S17 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S18 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S19 { get; internal set; }

        /// <summary>
        /// Number of self-described gender students aged x as at 31 dec
        /// </summary>
        public short? AGE_S20 { get; internal set; }

        /// <summary>
        /// Last write date
        /// </summary>
        public DateTime? LW_DATE { get; internal set; }

        /// <summary>
        /// Last write time
        /// </summary>
        public short? LW_TIME { get; internal set; }

        /// <summary>
        /// Last write operator
        /// [Uppercase Alphanumeric (128)]
        /// </summary>
        public string LW_USER { get; internal set; }

        #endregion

        #region Navigation Properties

        /// <summary>
        /// SCI (School Information) related entity by [KGH.CAMPUS]->[SCI.SCIKEY]
        /// Campus
        /// </summary>
        public SCI CAMPUS_SCI
        {
            get
            {
                if (CAMPUS == null)
                {
                    return null;
                }
                if (Cache_CAMPUS_SCI == null)
                {
                    Cache_CAMPUS_SCI = Context.SCI.FindBySCIKEY(CAMPUS.Value);
                }

                return Cache_CAMPUS_SCI;
            }
        }

        #endregion

        #region Foreign Navigation Properties

        /// <summary>
        /// SF (Staff) related entities by [KGH.KGHKEY]->[SF.HOUSE]
        /// (Was HOUSE) House code
        /// </summary>
        public IReadOnlyList<SF> KGHKEY_SF_HOUSE
        {
            get
            {
                if (Cache_KGHKEY_SF_HOUSE == null &&
                    !Context.SF.TryFindByHOUSE(KGHKEY, out Cache_KGHKEY_SF_HOUSE))
                {
                    Cache_KGHKEY_SF_HOUSE = new List<SF>().AsReadOnly();
                }

                return Cache_KGHKEY_SF_HOUSE;
            }
        }

        /// <summary>
        /// SG (Student Groupings) related entities by [KGH.KGHKEY]->[SG.HOUSE]
        /// (Was HOUSE) House code
        /// </summary>
        public IReadOnlyList<SG> KGHKEY_SG_HOUSE
        {
            get
            {
                if (Cache_KGHKEY_SG_HOUSE == null &&
                    !Context.SG.TryFindByHOUSE(KGHKEY, out Cache_KGHKEY_SG_HOUSE))
                {
                    Cache_KGHKEY_SG_HOUSE = new List<SG>().AsReadOnly();
                }

                return Cache_KGHKEY_SG_HOUSE;
            }
        }

        /// <summary>
        /// ST (Students) related entities by [KGH.KGHKEY]->[ST.HOUSE]
        /// (Was HOUSE) House code
        /// </summary>
        public IReadOnlyList<ST> KGHKEY_ST_HOUSE
        {
            get
            {
                if (Cache_KGHKEY_ST_HOUSE == null &&
                    !Context.ST.TryFindByHOUSE(KGHKEY, out Cache_KGHKEY_ST_HOUSE))
                {
                    Cache_KGHKEY_ST_HOUSE = new List<ST>().AsReadOnly();
                }

                return Cache_KGHKEY_ST_HOUSE;
            }
        }

        #endregion

    }
}


text:
The complete source code from my presentetion "Saving lives with RxJava"

This project let you get the current country code by checking the device's location
using GPS, Network Provider (GSM/CDMA) and IP (using IP-API service)
combined using RxJava.


text:
layout:        quilt
title:         The Easy Star Quilt that Wasn't Easy
date:          2012-03-10 00:00:00

tags: frontpage

columnCSS:     "large-6 columns"
css:           "height: 370px; width: 100%;"

featuredImage:       https://lh3.googleusercontent.com/-4ozODDpEMIw/UfbHdjpJJWI/AAAAAAAAARY/o0DYbXXVlbc/w470/photo.jpg
featuredImageOnPage: https://lh3.googleusercontent.com/-4ozODDpEMIw/UfbHdjpJJWI/AAAAAAAAARY/o0DYbXXVlbc/w1000/photo.jpg

imagesOnPage: [
               'https://lh5.googleusercontent.com/Hny-UxI2qaHk4wV6YcY3QNFAlfeqJs7rqMkSdvSwS3c=w303',
               'https://lh6.googleusercontent.com/iOk0D5gPxX0kZDPijUGN52SJ_Ad1ERFSi5BZHsSaCMk=w303',
               'https://lh6.googleusercontent.com/jhTVCxpTLHCmB1IXsH_lBOolRfM-ufimi2TIZ9aCIUQ=w303',
               'https://lh5.googleusercontent.com/f45a2rImQ0v1qBGn5qiAjh4NXo3JQhKOWi1LBSruobo=w303',
               'https://lh3.googleusercontent.com/D9d7lUr-5tKTy5iSuZ_DW5OEEHJ4D8DoBbOr-lWCvIE=w303',
               'https://lh6.googleusercontent.com/D5SuIxFy2ASJ-d3ZG6HSPVlPQbXv_vb_QOX2uQ-ik3E=w303',
               'https://lh3.googleusercontent.com/sTfKgOLQ2soM95_QiZ2fQFYXJXgJ9mWUZrXoPSzYlUI=w303',
               'https://lh6.googleusercontent.com/SnqgssWLzAMfOMJM56YjZIZuXBMMPswNTFAxZx8jZug=w303'
              ]
---

### by Patti McLain Fulton

I took this class several years ago.  The pattern was called Easy Star Sampler.  Well, it wasn't.  Since I'm always slow while working my quilts, I had the advantage of hearing all of the comments (some including tears and swear words).  So, when a very experienced friend of mine said that putting the blocks on point was too hard, I decided not to do that.  When the beautiful ribbon border brought another very experienced quilter to tears, I decided not to do that either.  So, I just did a straight set with sashing and cornerstones.  Then the quiltop just sat for a few years.

When Jackie began her long-arm business, I decided that this was the time to finish that quilt.  Well, Jackie and I spent about six hours on the phone choosing the quilting patterns.  It was well worth it.  The quilting that Jackie did truly makes the quilt.  It is so gorgeous.  Without the quilting it would be just another sampler.  A fellow quilter asked me why we chose to quilt it using a barn red color.  My response was, "So the quilting shows up".  I love this quilt because of the wonderful job that Jackie did.  I would highly recommend her to quilt your quilts.


text:
Plugin.define "Advanced-Guestbook" do
author "Andrew Horton"
version "0.3"
description "Web guestbook script. http://johnny.ihackstuff.com/ghdb/?function=detail&id=228 Version 2.2 is vulnerable http://www.securityfocus.com/bid/10209/info."
website "http://proxy2.de/scripts.php"

# Dorks #
dorks [
'inurl:guestbook.php "Advanced GuestBook" "powered by phpbb"'
]

# Matches #
matches [
{:certainty=>75, :ghdb=>'intitle:guestbook "advanced guestbook 2.2" powered'},
{:certainty=>75, :text=>"Thank you for stopping by my site. Here you can leave your mark."},
{:name=>"powered by", :version=>2.2, :regexp=>/Advanced Guestbook 2.2
\s+Powered by PHP/},

{:name=>"powered by - regexp", :version=>/(Advanced Guestbook) ([^<]+)/,
:offset=>1}
]

# Vuln version 2.2
# Advanced Guestbook 2.2

#  Powered by PHP & MySQL - http://http://www.proxy2.de

# Version 2.3.1
#Powered by Advanced Guestbook 2.3.1

# Version 2.3.3
#Advanced Guestbook 2.3.3

# Version 2.4.1
#Advanced Guestbook 2.4.1

# Version 2.4.3
#Advanced Guestbook 2.4.3

end


text:
using System.Windows.Input;
using System;
using System.Threading.Tasks;

namespace Prism
{
    /// <summary>
    /// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute"/> and <see cref="CanExecute"/>.
    /// </summary>
    public abstract class DelegateCommandBase : ICommand
    {
        private readonly Func<object, Task> _executeMethod;
        private readonly Func<object, bool> _canExecuteMethod;

        /// <summary>
        /// Creates a new instance of a <see cref="DelegateCommandBase"/>, specifying both the execute action and the can execute function.
        /// </summary>
        /// <param name="executeMethod">The <see cref="Action"/> to execute when <see cref="ICommand.Execute"/> is invoked.</param>
        /// <param name="canExecuteMethod">The <see cref="Func{Object,Bool}"/> to invoked when <see cref="ICommand.CanExecute"/> is invoked.</param>
        protected DelegateCommandBase(Action<object> executeMethod, Func<object, bool> canExecuteMethod)
        {
            if (executeMethod == null || canExecuteMethod == null)
                throw new ArgumentNullException("executeMethod");

            _executeMethod = (arg) => { executeMethod(arg); return Task.Delay(0); };
            _canExecuteMethod = canExecuteMethod;
        }

        /// <summary>
        /// Creates a new instance of a <see cref="DelegateCommandBase"/>, specifying both the Execute action as an awaitable Task and the CanExecute function.
        /// </summary>
        /// <param name="executeMethod">The <see cref="Func{Object,Task}"/> to execute when <see cref="ICommand.Execute"/> is invoked.</param>
        /// <param name="canExecuteMethod">The <see cref="Func{Object,Bool}"/> to invoked when <see cref="ICommand.CanExecute"/> is invoked.</param>
        protected DelegateCommandBase(Func<object,Task> executeMethod, Func<object, bool> canExecuteMethod)
        {
            if (executeMethod == null || canExecuteMethod == null)
                throw new ArgumentNullException("executeMethod");

            _executeMethod = executeMethod;
            _canExecuteMethod = canExecuteMethod;
        }

        /// <summary>
        /// Raises <see cref="ICommand.CanExecuteChanged"/> on the UI thread so every
        /// command invoker can requery <see cref="ICommand.CanExecute"/>.
        /// </summary>
        protected virtual void OnCanExecuteChanged()
        {
            var handlers = CanExecuteChanged;
            if (handlers != null)
            {
                handlers(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Raises <see cref="DelegateCommandBase.CanExecuteChanged"/> on the UI thread so every command invoker
        /// can requery to check if the command can execute.
        /// <remarks>Note that this will trigger the execution of <see cref="DelegateCommandBase.CanExecute"/> once for each invoker.</remarks>
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
        public void RaiseCanExecuteChanged()
        {
            OnCanExecuteChanged();
        }

        async void ICommand.Execute(object parameter)
        {
            await Execute(parameter);
        }

        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute(parameter);
        }

        /// <summary>
        /// Executes the command with the provided parameter by invoking the <see cref="Action{Object}"/> supplied during construction.
        /// </summary>
        /// <param name="parameter"></param>
        protected async Task Execute(object parameter)
        {
            await _executeMethod(parameter);
        }

        /// <summary>
        /// Determines if the command can execute with the provided parameter by invoking the <see cref="Func{Object,Bool}"/> supplied during construction.
        /// </summary>
        /// <param name="parameter">The parameter to use when determining if this command can execute.</param>
        /// <returns>Returns <see langword="true"/> if the command can execute.  <see langword="False"/> otherwise.</returns>
        protected bool CanExecute(object parameter)
        {
            return _canExecuteMethod == null || _canExecuteMethod(parameter);
        }

        /// <summary>
        /// Occurs when changes happen that affect whether or not the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged;

    }
}


text:
import os
import re
import shutil
import textwrap
import uuid
from dataclasses import dataclass
from enum import Enum
from hashlib import sha256
from pathlib import Path
from textwrap import dedent
from typing import Callable, Dict, List, Tuple

import pytest

from pip._internal.cli.status_codes import ERROR
from pip._internal.utils.urls import path_to_url
from tests.conftest import MockServer, ScriptFactory
from tests.lib import (
    PipTestEnvironment,
    TestData,
    TestPipResult,
    create_basic_sdist_for_package,
    create_really_basic_wheel,
)
from tests.lib.server import file_response

def fake_wheel(data: TestData, wheel_path: str) -> None:
    wheel_name = os.path.basename(wheel_path)
    name, version, rest = wheel_name.split("-", 2)
    wheel_data = create_really_basic_wheel(name, version)
    data.packages.joinpath(wheel_path).write_bytes(wheel_data)

@pytest.mark.network
def test_download_if_requested(script: PipTestEnvironment) -> None:
    """
    It should download (in the scratch path) and not install if requested.
    """
    result = script.pip("download", "-d", "pip_downloads", "INITools==0.1")
    result.did_create(Path("scratch") / "pip_downloads" / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")

@pytest.mark.network
def test_basic_download_setuptools(script: PipTestEnvironment) -> None:
    """
    It should download (in the scratch path) and not install if requested.
    """
    result = script.pip("download", "setuptools")
    setuptools_prefix = str(Path("scratch") / "setuptools")
    assert any(os.fspath(p).startswith(setuptools_prefix) for p in result.files_created)

def test_download_wheel(script: PipTestEnvironment, data: TestData) -> None:
    """
    Test using "pip download" to download a *.whl archive.
    """
    result = script.pip(
        "download", "--no-index", "-f", data.packages, "-d", ".", "meta"
    )
    result.did_create(Path("scratch") / "meta-1.0-py2.py3-none-any.whl")
    result.did_not_create(script.site_packages / "piptestpackage")

@pytest.mark.network
def test_single_download_from_requirements_file(script: PipTestEnvironment) -> None:
    """
    It should support download (in the scratch path) from PyPI from a
    requirements file
    """
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
        INITools==0.1
        """
        )
    )
    result = script.pip(
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "-d",
        ".",
    )
    result.did_create(Path("scratch") / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")

@pytest.mark.network
def test_basic_download_should_download_dependencies(
    script: PipTestEnvironment,
) -> None:
    """
    It should download dependencies (in the scratch path)
    """
    result = script.pip("download", "Paste[openid]==1.7.5.1", "-d", ".")
    result.did_create(Path("scratch") / "Paste-1.7.5.1.tar.gz")
    openid_tarball_prefix = str(Path("scratch") / "python-openid-")
    assert any(
        os.fspath(path).startswith(openid_tarball_prefix)
        for path in result.files_created
    )
    result.did_not_create(script.site_packages / "openid")

def test_download_wheel_archive(script: PipTestEnvironment, data: TestData) -> None:
    """
    It should download a wheel archive path
    """
    wheel_filename = "colander-0.9.9-py2.py3-none-any.whl"
    wheel_path = "/".join((data.find_links, wheel_filename))
    result = script.pip("download", wheel_path, "-d", ".", "--no-deps")
    result.did_create(Path("scratch") / wheel_filename)

def test_download_should_download_wheel_deps(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    It should download dependencies for wheels(in the scratch path)
    """
    wheel_filename = "colander-0.9.9-py2.py3-none-any.whl"
    dep_filename = "translationstring-1.1.tar.gz"
    wheel_path = "/".join((data.find_links, wheel_filename))
    result = script.pip(
        "download", wheel_path, "-d", ".", "--find-links", data.find_links, "--no-index"
    )
    result.did_create(Path("scratch") / wheel_filename)
    result.did_create(Path("scratch") / dep_filename)

@pytest.mark.network
def test_download_should_skip_existing_files(script: PipTestEnvironment) -> None:
    """
    It should not download files already existing in the scratch dir
    """
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
        INITools==0.1
        """
        )
    )

    result = script.pip(
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "-d",
        ".",
    )
    result.did_create(Path("scratch") / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")

    # adding second package to test-req.txt
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
        INITools==0.1
        python-openid==2.2.5
        """
        )
    )

    # only the second package should be downloaded
    result = script.pip(
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "-d",
        ".",
    )
    openid_tarball_prefix = str(Path("scratch") / "python-openid-")
    assert any(
        os.fspath(path).startswith(openid_tarball_prefix)
        for path in result.files_created
    )
    result.did_not_create(Path("scratch") / "INITools-0.1.tar.gz")
    result.did_not_create(script.site_packages / "initools")
    result.did_not_create(script.site_packages / "openid")

@pytest.mark.network
def test_download_vcs_link(script: PipTestEnvironment) -> None:
    """
    It should allow -d flag for vcs links, regression test for issue #798.
    """
    result = script.pip(
        "download", "-d", ".", "git+https://github.com/pypa/pip-test-package.git"
    )
    result.did_create(Path("scratch") / "pip-test-package-0.1.1.zip")
    result.did_not_create(script.site_packages / "piptestpackage")

def test_only_binary_set_then_download_specific_platform(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    Confirm that specifying an interpreter/platform constraint
    is allowed when ``--only-binary=:all:`` is set.
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

def test_no_deps_set_then_download_specific_platform(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    Confirm that specifying an interpreter/platform constraint
    is allowed when ``--no-deps`` is set.
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--no-deps",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

def test_download_specific_platform_fails(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    Confirm that specifying an interpreter/platform constraint
    enforces that ``--no-deps`` or ``--only-binary=:all:`` is set.
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
        expect_error=True,
    )
    assert "--only-binary=:all:" in result.stderr

def test_no_binary_set_then_download_specific_platform_fails(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    Confirm that specifying an interpreter/platform constraint
    enforces that ``--only-binary=:all:`` is set without ``--no-binary``.
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--no-binary=fake",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
        expect_error=True,
    )
    assert "--only-binary=:all:" in result.stderr

def test_download_specify_platform(script: PipTestEnvironment, data: TestData) -> None:
    """
    Test using "pip download --platform" to download a .whl archive
    supported for a specific platform
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")

    # Confirm that universal wheels are returned even for specific
    # platforms.
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "macosx_10_9_x86_64",
        "fake",
    )

    data.reset()
    fake_wheel(data, "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl")
    fake_wheel(data, "fake-2.0-py2.py3-none-linux_x86_64.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "macosx_10_10_x86_64",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-macosx_10_9_x86_64.whl")

    # OSX platform wheels are not backward-compatible.
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "macosx_10_8_x86_64",
        "fake",
        expect_error=True,
    )

    # No linux wheel provided for this version.
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake==1",
        expect_error=True,
    )

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "linux_x86_64",
        "fake==2",
    )
    result.did_create(Path("scratch") / "fake-2.0-py2.py3-none-linux_x86_64.whl")

    # Test with multiple supported platforms specified.
    data.reset()
    fake_wheel(data, "fake-3.0-py2.py3-none-linux_x86_64.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--platform",
        "manylinux1_x86_64",
        "--platform",
        "linux_x86_64",
        "--platform",
        "any",
        "fake==3",
    )
    result.did_create(Path("scratch") / "fake-3.0-py2.py3-none-linux_x86_64.whl")

class TestDownloadPlatformManylinuxes:
    """
    "pip download --platform" downloads a .whl archive supported for
    manylinux platforms.
    """

    @pytest.mark.parametrize(
        "platform",
        [
            "linux_x86_64",
            "manylinux1_x86_64",
            "manylinux2010_x86_64",
            "manylinux2014_x86_64",
        ],
    )
    def test_download_universal(
        self, platform: str, script: PipTestEnvironment, data: TestData
    ) -> None:
        """
        Universal wheels are returned even for specific platforms.
        """
        fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
        result = script.pip(
            "download",
            "--no-index",
            "--find-links",
            data.find_links,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--platform",
            platform,
            "fake",
        )
        result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

    @pytest.mark.parametrize(
        "wheel_abi,platform",
        [
            ("manylinux1_x86_64", "manylinux1_x86_64"),
            ("manylinux1_x86_64", "manylinux2010_x86_64"),
            ("manylinux2010_x86_64", "manylinux2010_x86_64"),
            ("manylinux1_x86_64", "manylinux2014_x86_64"),
            ("manylinux2010_x86_64", "manylinux2014_x86_64"),
            ("manylinux2014_x86_64", "manylinux2014_x86_64"),
        ],
    )
    def test_download_compatible_manylinuxes(
        self,
        wheel_abi: str,
        platform: str,
        script: PipTestEnvironment,
        data: TestData,
    ) -> None:
        """
        Earlier manylinuxes are compatible with later manylinuxes.
        """
        wheel = f"fake-1.0-py2.py3-none-{wheel_abi}.whl"
        fake_wheel(data, wheel)
        result = script.pip(
            "download",
            "--no-index",
            "--find-links",
            data.find_links,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--platform",
            platform,
            "fake",
        )
        result.did_create(Path("scratch") / wheel)

    def test_explicit_platform_only(
        self, data: TestData, script: PipTestEnvironment
    ) -> None:
        """
        When specifying the platform, manylinux1 needs to be the
        explicit platform--it won't ever be added to the compatible
        tags.
        """
        fake_wheel(data, "fake-1.0-py2.py3-none-linux_x86_64.whl")
        script.pip(
            "download",
            "--no-index",
            "--find-links",
            data.find_links,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--platform",
            "linux_x86_64",
            "fake",
        )

def test_download__python_version(script: PipTestEnvironment, data: TestData) -> None:
    """
    Test using "pip download --python-version" to download a .whl archive
    supported for a specific interpreter
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "3",
        "fake",
    )

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "27",
        "fake",
    )

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "33",
        "fake",
    )

    data.reset()
    fake_wheel(data, "fake-1.0-py2-none-any.whl")
    fake_wheel(data, "fake-2.0-py3-none-any.whl")

    # No py3 provided for version 1.
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "3",
        "fake==1.0",
        expect_error=True,
    )

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "26",
        "fake",
    )

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "3",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-2.0-py3-none-any.whl")

def make_wheel_with_python_requires(
    script: PipTestEnvironment, package_name: str, python_requires: str
) -> Path:
    """
    Create a wheel using the given python_requires.

    :return: the path to the wheel file.
    """
    package_dir = script.scratch_path / package_name
    package_dir.mkdir()

    text = textwrap.dedent(
        """\
    from setuptools import setup
    setup(name='{}',
          python_requires='{}',
          version='1.0')
    """
    ).format(package_name, python_requires)
    package_dir.joinpath("setup.py").write_text(text)
    script.run(
        "python",
        "setup.py",
        "bdist_wheel",
        "--universal",
        cwd=package_dir,
    )

    file_name = f"{package_name}-1.0-py2.py3-none-any.whl"
    return package_dir / "dist" / file_name

@pytest.mark.usefixtures("with_wheel")
def test_download__python_version_used_for_python_requires(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    Test that --python-version is used for the Requires-Python check.
    """
    wheel_path = make_wheel_with_python_requires(
        script,
        "mypackage",
        python_requires="==3.2",
    )
    wheel_dir = os.path.dirname(wheel_path)

    def make_args(python_version: str) -> List[str]:
        return [
            "download",
            "--no-index",
            "--find-links",
            wheel_dir,
            "--only-binary=:all:",
            "--dest",
            ".",
            "--python-version",
            python_version,
            "mypackage==1.0",
        ]

    args = make_args("33")
    result = script.pip(*args, expect_error=True)
    expected_err = (
        "ERROR: Package 'mypackage' requires a different Python: "
        "3.3.0 not in '==3.2'"
    )
    assert expected_err in result.stderr, f"stderr: {result.stderr}"

    # Now try with a --python-version that satisfies the Requires-Python.
    args = make_args("32")
    script.pip(*args)  # no exception

@pytest.mark.usefixtures("with_wheel")
def test_download_ignore_requires_python_dont_fail_with_wrong_python(
    script: PipTestEnvironment,
) -> None:
    """
    Test that --ignore-requires-python ignores Requires-Python check.
    """
    wheel_path = make_wheel_with_python_requires(
        script,
        "mypackage",
        python_requires="==999",
    )
    wheel_dir = os.path.dirname(wheel_path)

    result = script.pip(
        "download",
        "--ignore-requires-python",
        "--no-index",
        "--find-links",
        wheel_dir,
        "--only-binary=:all:",
        "--dest",
        ".",
        "mypackage==1.0",
    )
    result.did_create(Path("scratch") / "mypackage-1.0-py2.py3-none-any.whl")

def test_download_specify_abi(script: PipTestEnvironment, data: TestData) -> None:
    """
    Test using "pip download --abi" to download a .whl archive
    supported for a specific abi
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--abi",
        "fake_abi",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--abi",
        "none",
        "fake",
    )

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--abi",
        "cp27m",
        "fake",
    )

    data.reset()
    fake_wheel(data, "fake-1.0-fk2-fakeabi-fake_platform.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "--implementation",
        "fk",
        "--platform",
        "fake_platform",
        "--abi",
        "fakeabi",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-fk2-fakeabi-fake_platform.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--platform",
        "fake_platform",
        "--abi",
        "none",
        "fake",
        expect_error=True,
    )

    data.reset()
    fake_wheel(data, "fake-1.0-fk2-otherabi-fake_platform.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--python-version",
        "2",
        "--implementation",
        "fk",
        "--platform",
        "fake_platform",
        "--abi",
        "fakeabi",
        "--abi",
        "otherabi",
        "--abi",
        "none",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-fk2-otherabi-fake_platform.whl")

def test_download_specify_implementation(
    script: PipTestEnvironment, data: TestData
) -> None:
    """
    Test using "pip download --abi" to download a .whl archive
    supported for a specific abi
    """
    fake_wheel(data, "fake-1.0-py2.py3-none-any.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-py2.py3-none-any.whl")

    data.reset()
    fake_wheel(data, "fake-1.0-fk3-none-any.whl")
    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--python-version",
        "3",
        "fake",
    )
    result.did_create(Path("scratch") / "fake-1.0-fk3-none-any.whl")

    result = script.pip(
        "download",
        "--no-index",
        "--find-links",
        data.find_links,
        "--only-binary=:all:",
        "--dest",
        ".",
        "--implementation",
        "fk",
        "--python-version",
        "2",
        "fake",
        expect_error=True,
    )

def test_download_exit_status_code_when_no_requirements(
    script: PipTestEnvironment,
) -> None:
    """
    Test download exit status code when no requirements specified
    """
    result = script.pip("download", expect_error=True)
    assert "You must give at least one requirement to download" in result.stderr
    assert result.returncode == ERROR

def test_download_exit_status_code_when_blank_requirements_file(
    script: PipTestEnvironment,
) -> None:
    """
    Test download exit status code when blank requirements file specified
    """
    script.scratch_path.joinpath("blank.txt").write_text("\n")
    script.pip("download", "-r", "blank.txt")

def test_download_prefer_binary_when_tarball_higher_than_wheel(
    script: PipTestEnvironment, data: TestData
) -> None:
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    result = script.pip(
        "download",
        "--prefer-binary",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "source",
    )
    result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
    result.did_not_create(Path("scratch") / "source-1.0.tar.gz")

def test_prefer_binary_tarball_higher_than_wheel_req_file(
    script: PipTestEnvironment, data: TestData
) -> None:
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
                --prefer-binary
                 source
                """
        )
    )
    result = script.pip(
        "download",
        "-r",
        script.scratch_path / "test-req.txt",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
    )

    result.did_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")
    result.did_not_create(Path("scratch") / "source-1.0.tar.gz")

def test_download_prefer_binary_when_wheel_doesnt_satisfy_req(
    script: PipTestEnvironment, data: TestData
) -> None:
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
        source>0.9
        """
        )
    )

    result = script.pip(
        "download",
        "--prefer-binary",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "-r",
        script.scratch_path / "test-req.txt",
    )
    result.did_create(Path("scratch") / "source-1.0.tar.gz")
    result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")

def test_prefer_binary_when_wheel_doesnt_satisfy_req_req_file(
    script: PipTestEnvironment, data: TestData
) -> None:
    fake_wheel(data, "source-0.8-py2.py3-none-any.whl")
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
        --prefer-binary
        source>0.9
        """
        )
    )

    result = script.pip(
        "download",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "-r",
        script.scratch_path / "test-req.txt",
    )
    result.did_create(Path("scratch") / "source-1.0.tar.gz")
    result.did_not_create(Path("scratch") / "source-0.8-py2.py3-none-any.whl")

def test_download_prefer_binary_when_only_tarball_exists(
    script: PipTestEnvironment, data: TestData
) -> None:
    result = script.pip(
        "download",
        "--prefer-binary",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "source",
    )
    result.did_create(Path("scratch") / "source-1.0.tar.gz")

def test_prefer_binary_when_only_tarball_exists_req_file(
    script: PipTestEnvironment, data: TestData
) -> None:
    script.scratch_path.joinpath("test-req.txt").write_text(
        textwrap.dedent(
            """
            --prefer-binary
            source
            """
        )
    )
    result = script.pip(
        "download",
        "--no-index",
        "-f",
        data.packages,
        "-d",
        ".",
        "-r",
        script.scratch_path / "test-req.txt",
    )
    result.did_create(Path("scratch") / "source-1.0.tar.gz")

@pytest.fixture(scope="session")
def shared_script(
    tmpdir_factory: pytest.TempPathFactory, script_factory: ScriptFactory
) -> PipTestEnvironment:
    tmpdir = tmpdir_factory.mktemp("download_shared_script")
    script = script_factory(tmpdir.joinpath("workspace"))
    return script

def test_download_file_url(
    shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
) -> None:
    download_dir = tmpdir / "download"
    download_dir.mkdir()
    downloaded_path = download_dir / "simple-1.0.tar.gz"

    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"

    shared_script.pip(
        "download",
        "-d",
        str(download_dir),
        "--no-index",
        simple_pkg.as_uri(),
    )

    assert downloaded_path.exists()
    assert simple_pkg.read_bytes() == downloaded_path.read_bytes()

def test_download_file_url_existing_ok_download(
    shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
) -> None:
    download_dir = tmpdir / "download"
    download_dir.mkdir()
    downloaded_path = download_dir / "simple-1.0.tar.gz"
    fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
    shutil.copy(str(fake_existing_package), str(downloaded_path))
    downloaded_path_bytes = downloaded_path.read_bytes()

    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
    url = f"{simple_pkg.as_uri()}#sha256={sha256(downloaded_path_bytes).hexdigest()}"

    shared_script.pip("download", "-d", str(download_dir), url)

    assert downloaded_path_bytes == downloaded_path.read_bytes()

def test_download_file_url_existing_bad_download(
    shared_script: PipTestEnvironment, shared_data: TestData, tmpdir: Path
) -> None:
    download_dir = tmpdir / "download"
    download_dir.mkdir()
    downloaded_path = download_dir / "simple-1.0.tar.gz"
    fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
    shutil.copy(str(fake_existing_package), str(downloaded_path))

    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
    simple_pkg_bytes = simple_pkg.read_bytes()
    url = f"{simple_pkg.as_uri()}#sha256={sha256(simple_pkg_bytes).hexdigest()}"

    result = shared_script.pip(
        "download",
        "-d",
        str(download_dir),
        url,
        allow_stderr_warning=True,  # bad hash
    )

    assert simple_pkg_bytes == downloaded_path.read_bytes()
    assert "WARNING: Previously-downloaded file" in result.stderr
    assert "has bad hash. Re-downloading." in result.stderr

def test_download_http_url_bad_hash(
    shared_script: PipTestEnvironment,
    shared_data: TestData,
    tmpdir: Path,
    mock_server: MockServer,
) -> None:
    """
    If already-downloaded file has bad checksum, re-download.
    """
    download_dir = tmpdir / "download"
    download_dir.mkdir()
    downloaded_path = download_dir / "simple-1.0.tar.gz"
    fake_existing_package = shared_data.packages / "simple-2.0.tar.gz"
    shutil.copy(str(fake_existing_package), str(downloaded_path))

    simple_pkg = shared_data.packages / "simple-1.0.tar.gz"
    simple_pkg_bytes = simple_pkg.read_bytes()
    digest = sha256(simple_pkg_bytes).hexdigest()
    mock_server.set_responses([file_response(simple_pkg)])
    mock_server.start()
    base_address = f"http://{mock_server.host}:{mock_server.port}"
    url = f"{base_address}/simple-1.0.tar.gz#sha256={digest}"

    result = shared_script.pip(
        "download",
        "-d",
        str(download_dir),
        url,
        allow_stderr_warning=True,  # bad hash
    )

    assert simple_pkg_bytes == downloaded_path.read_bytes()
    assert "WARNING: Previously-downloaded file" in result.stderr
    assert "has bad hash. Re-downloading." in result.stderr

    mock_server.stop()
    requests = mock_server.get_requests()
    assert len(requests) == 1
    assert requests[0]["PATH_INFO"] == "/simple-1.0.tar.gz"
    assert requests[0]["HTTP_ACCEPT_ENCODING"] == "identity"

def test_download_editable(
    script: PipTestEnvironment, data: TestData, tmpdir: Path
) -> None:
    """
    Test 'pip download' of editables in requirement file.
    """
    editable_path = str(data.src / "simplewheel-1.0").replace(os.path.sep, "/")
    requirements_path = tmpdir / "requirements.txt"
    requirements_path.write_text("-e " + editable_path + "\n")
    download_dir = tmpdir / "download_dir"
    script.pip(
        "download", "--no-deps", "-r", str(requirements_path), "-d", str(download_dir)
    )
    downloads = os.listdir(download_dir)
    assert len(downloads) == 1
    assert downloads[0].endswith(".zip")

def test_download_use_pep517_propagation(
    script: PipTestEnvironment, tmpdir: Path, common_wheels: Path
) -> None:
    """
    Check that --use-pep517 applies not just to the requirements specified
    on the command line, but to their dependencies too.
    """

    create_basic_sdist_for_package(script, "fake_proj", "1.0", depends=["fake_dep"])

    # If --use-pep517 is in effect, then setup.py should be running in an isolated
    # environment that doesn't have pip in it.
    create_basic_sdist_for_package(
        script,
        "fake_dep",
        "1.0",
        setup_py_prelude=textwrap.dedent(
            """\
            try:
                import pip
            except ImportError:
                pass
            else:
                raise Exception(f"not running in isolation")
            """
        ),
    )

    download_dir = tmpdir / "download_dir"
    script.pip(
        "download",
        f"--dest={download_dir}",
        "--no-index",
        f"--find-links={common_wheels}",
        f"--find-links={script.scratch_path}",
        "--use-pep517",
        "fake_proj",
    )

    downloads = os.listdir(download_dir)
    assert len(downloads) == 2

class MetadataKind(Enum):
    """All the types of values we might be provided for the data-dist-info-metadata
    attribute from PEP 658."""

    # Valid: will read metadata from the dist instead.
    No = "none"
    # Valid: will read the .metadata file, but won't check its hash.
    Unhashed = "unhashed"
    # Valid: will read the .metadata file and check its hash matches.
    Sha256 = "sha256"
    # Invalid: will error out after checking the hash.
    WrongHash = "wrong-hash"
    # Invalid: will error out after failing to fetch the .metadata file.
    NoFile = "no-file"

@dataclass(frozen=True)
class Package:
    """Mock package structure used to generate a PyPI repository.

    Package name and version should correspond to sdists (.tar.gz files) in our test
    data."""

    name: str
    version: str
    filename: str
    metadata: MetadataKind
    # This will override any dependencies specified in the actual dist's METADATA.
    requires_dist: Tuple[str, ...] = ()

    def metadata_filename(self) -> str:
        """This is specified by PEP 658."""
        return f"{self.filename}.metadata"

    def generate_additional_tag(self) -> str:
        """This gets injected into the <a> tag in the generated PyPI index page for this
        package."""
        if self.metadata == MetadataKind.No:
            return ""
        if self.metadata in [MetadataKind.Unhashed, MetadataKind.NoFile]:
            return 'data-dist-info-metadata="true"'
        if self.metadata == MetadataKind.WrongHash:
            return 'data-dist-info-metadata="sha256=WRONG-HASH"'
        assert self.metadata == MetadataKind.Sha256
        checksum = sha256(self.generate_metadata()).hexdigest()
        return f'data-dist-info-metadata="sha256={checksum}"'

    def requires_str(self) -> str:
        if not self.requires_dist:
            return ""
        joined = " and ".join(self.requires_dist)
        return f"Requires-Dist: {joined}"

    def generate_metadata(self) -> bytes:
        """This is written to `self.metadata_filename()` and will override the actual
        dist's METADATA, unless `self.metadata == MetadataKind.NoFile`."""
        return dedent(
            f"""\
        Metadata-Version: 2.1
        Name: {self.name}
        Version: {self.version}
        {self.requires_str()}
        """
        ).encode("utf-8")

@pytest.fixture(scope="function")
def write_index_html_content(tmpdir: Path) -> Callable[[str], Path]:
    """Generate a PyPI package index.html within a temporary local directory."""
    html_dir = tmpdir / "index_html_content"
    html_dir.mkdir()

    def generate_index_html_subdir(index_html: str) -> Path:
        """Create a new subdirectory after a UUID and write an index.html."""
        new_subdir = html_dir / uuid.uuid4().hex
        new_subdir.mkdir()

        with open(new_subdir / "index.html", "w") as f:
            f.write(index_html)

        return new_subdir

    return generate_index_html_subdir

@pytest.fixture(scope="function")
def html_index_for_packages(
    shared_data: TestData,
    write_index_html_content: Callable[[str], Path],
) -> Callable[..., Path]:
    """Generate a PyPI HTML package index within a local directory pointing to
    blank data."""

    def generate_html_index_for_packages(packages: Dict[str, List[Package]]) -> Path:
        """
        Produce a PyPI directory structure pointing to the specified packages.
        """
        # (1) Generate the content for a PyPI index.html.
        pkg_links = "\n".join(
            f'    <a href="{pkg}/index.html">{pkg}</a>' for pkg in packages.keys()
        )
        index_html = f"""\
<!DOCTYPE html>
<html>
  <head>
    <meta name="pypi:repository-version" content="1.0">
    <title>Simple index</title>
  </head>
  <body>
{pkg_links}
  </body>
</html>"""
        # (2) Generate the index.html in a new subdirectory of the temp directory.
        index_html_subdir = write_index_html_content(index_html)

        # (3) Generate subdirectories for individual packages, each with their own
        # index.html.
        for pkg, links in packages.items():
            pkg_subdir = index_html_subdir / pkg
            pkg_subdir.mkdir()

            download_links: List[str] = []
            for package_link in links:
                # (3.1) Generate the <a> tag which pip can crawl pointing to this
                # specific package version.
                download_links.append(
                    f'    <a href="{package_link.filename}" {package_link.generate_additional_tag()}>{package_link.filename}</a><br/>'  # noqa: E501
                )
                # (3.2) Copy over the corresponding file in `shared_data.packages`.
                shutil.copy(
                    shared_data.packages / package_link.filename,
                    pkg_subdir / package_link.filename,
                )
                # (3.3) Write a metadata file, if applicable.
                if package_link.metadata != MetadataKind.NoFile:
                    with open(pkg_subdir / package_link.metadata_filename(), "wb") as f:
                        f.write(package_link.generate_metadata())

            # (3.4) After collating all the download links and copying over the files,
            # write an index.html with the generated download links for each
            # copied file for this specific package name.
            download_links_str = "\n".join(download_links)
            pkg_index_content = f"""\
<!DOCTYPE html>
<html>
  <head>
    <meta name="pypi:repository-version" content="1.0">
    <title>Links for {pkg}</title>
  </head>
  <body>
    <h1>Links for {pkg}</h1>
{download_links_str}
  </body>
</html>"""
            with open(pkg_subdir / "index.html", "w") as f:
                f.write(pkg_index_content)

        return index_html_subdir

    return generate_html_index_for_packages

@pytest.fixture(scope="function")
def download_generated_html_index(
    script: PipTestEnvironment,
    html_index_for_packages: Callable[[Dict[str, List[Package]]], Path],
    tmpdir: Path,
) -> Callable[..., Tuple[TestPipResult, Path]]:
    """Execute `pip download` against a generated PyPI index."""
    download_dir = tmpdir / "download_dir"

    def run_for_generated_index(
        packages: Dict[str, List[Package]],
        args: List[str],
        allow_error: bool = False,
    ) -> Tuple[TestPipResult, Path]:
        """
        Produce a PyPI directory structure pointing to the specified packages, then
        execute `pip download -i ...` pointing to our generated index.
        """
        index_dir = html_index_for_packages(packages)
        pip_args = [
            "download",
            "-d",
            str(download_dir),
            "-i",
            path_to_url(str(index_dir)),
            *args,
        ]
        result = script.pip(*pip_args, allow_error=allow_error)
        return (result, download_dir)

    return run_for_generated_index

# The package database we generate for testing PEP 658 support.
_simple_packages: Dict[str, List[Package]] = {
    "simple": [
        Package("simple", "1.0", "simple-1.0.tar.gz", MetadataKind.Sha256),
        Package("simple", "2.0", "simple-2.0.tar.gz", MetadataKind.No),
        # This will raise a hashing error.
        Package("simple", "3.0", "simple-3.0.tar.gz", MetadataKind.WrongHash),
    ],
    "simple2": [
        # Override the dependencies here in order to force pip to download
        # simple-1.0.tar.gz as well.
        Package(
            "simple2",
            "1.0",
            "simple2-1.0.tar.gz",
            MetadataKind.Unhashed,
            ("simple==1.0",),
        ),
        # This will raise an error when pip attempts to fetch the metadata file.
        Package("simple2", "2.0", "simple2-2.0.tar.gz", MetadataKind.NoFile),
    ],
    "colander": [
        # Ensure we can read the dependencies from a metadata file within a wheel
        # *without* PEP 658 metadata.
        Package(
            "colander", "0.9.9", "colander-0.9.9-py2.py3-none-any.whl", MetadataKind.No
        ),
    ],
    "compilewheel": [
        # Ensure we can override the dependencies of a wheel file by injecting PEP
        # 658 metadata.
        Package(
            "compilewheel",
            "1.0",
            "compilewheel-1.0-py2.py3-none-any.whl",
            MetadataKind.Unhashed,
            ("simple==1.0",),
        ),
    ],
    "has-script": [
        # Ensure we check PEP 658 metadata hashing errors for wheel files.
        Package(
            "has-script",
            "1.0",
            "has.script-1.0-py2.py3-none-any.whl",
            MetadataKind.WrongHash,
        ),
    ],
    "translationstring": [
        Package(
            "translationstring", "1.1", "translationstring-1.1.tar.gz", MetadataKind.No
        ),
    ],
    "priority": [
        # Ensure we check for a missing metadata file for wheels.
        Package(
            "priority", "1.0", "priority-1.0-py2.py3-none-any.whl", MetadataKind.NoFile
        ),
    ],
}

@pytest.mark.parametrize(
    "requirement_to_download, expected_outputs",
    [
        ("simple2==1.0", ["simple-1.0.tar.gz", "simple2-1.0.tar.gz"]),
        ("simple==2.0", ["simple-2.0.tar.gz"]),
        (
            "colander",
            ["colander-0.9.9-py2.py3-none-any.whl", "translationstring-1.1.tar.gz"],
        ),
        (
            "compilewheel",
            ["compilewheel-1.0-py2.py3-none-any.whl", "simple-1.0.tar.gz"],
        ),
    ],
)
def test_download_metadata(
    download_generated_html_index: Callable[..., Tuple[TestPipResult, Path]],
    requirement_to_download: str,
    expected_outputs: List[str],
) -> None:
    """Verify that if a data-dist-info-metadata attribute is present, then it is used
    instead of the actual dist's METADATA."""
    _, download_dir = download_generated_html_index(
        _simple_packages,
        [requirement_to_download],
    )
    assert sorted(os.listdir(download_dir)) == expected_outputs

@pytest.mark.parametrize(
    "requirement_to_download, real_hash",
    [
        (
            "simple==3.0",
            "95e0f200b6302989bcf2cead9465cf229168295ea330ca30d1ffeab5c0fed996",
        ),
        (
            "has-script",
            "16ba92d7f6f992f6de5ecb7d58c914675cf21f57f8e674fb29dcb4f4c9507e5b",
        ),
    ],
)
def test_incorrect_metadata_hash(
    download_generated_html_index: Callable[..., Tuple[TestPipResult, Path]],
    requirement_to_download: str,
    real_hash: str,
) -> None:
    """Verify that if a hash for data-dist-info-metadata is provided, it must match the
    actual hash of the metadata file."""
    result, _ = download_generated_html_index(
        _simple_packages,
        [requirement_to_download],
        allow_error=True,
    )
    assert result.returncode != 0
    expected_msg = f"""\
        Expected sha256 WRONG-HASH
             Got        {real_hash}"""
    assert expected_msg in result.stderr

@pytest.mark.parametrize(
    "requirement_to_download, expected_url",
    [
        ("simple2==2.0", "simple2-2.0.tar.gz.metadata"),
        ("priority", "priority-1.0-py2.py3-none-any.whl.metadata"),
    ],
)
def test_metadata_not_found(
    download_generated_html_index: Callable[..., Tuple[TestPipResult, Path]],
    requirement_to_download: str,
    expected_url: str,
) -> None:
    """Verify that if a data-dist-info-metadata attribute is provided, that pip will
    fetch the .metadata file at the location specified by PEP 658, and error
    if unavailable."""
    result, _ = download_generated_html_index(
        _simple_packages,
        [requirement_to_download],
        allow_error=True,
    )
    assert result.returncode != 0
    expected_re = re.escape(expected_url)
    pattern = re.compile(
        f"ERROR: 404 Client Error: FileNotFoundError for url:.*{expected_re}"
    )
    assert pattern.search(result.stderr), (pattern, result.stderr)